/*
TessesFramework a library to make C++ easier for me, used in CrossLang:
https://git.tesses.org/tesses50/crosslang
Copyright (C) 2026 Mike Nolan
SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "TessesFramework/Crypto/Crypto.hpp"
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
#include
#include
#include
#include
#include
#include
#include
#endif
#include
namespace Tesses::Framework::Crypto {
bool HaveCrypto() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
return true;
#else
return false;
#endif
}
std::string Base64_Encode(std::vector data) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
std::string str = {};
size_t olen = 0;
mbedtls_base64_encode((uint8_t *)str.data(), 0, &olen, data.data(),
data.size());
str.resize(olen - 1);
if (mbedtls_base64_encode((uint8_t *)str.data(), olen, &olen, data.data(),
data.size()) == 0) {
return str;
}
#endif
return "";
}
std::vector Base64_Decode(std::string str) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
size_t olen = 0;
std::vector data;
mbedtls_base64_decode(data.data(), 0, &olen, (const uint8_t *)str.data(),
str.size());
data.resize(olen);
if (mbedtls_base64_decode(data.data(), olen, &olen,
(const uint8_t *)str.data(), str.size()) == 0) {
return data;
}
#endif
return {};
}
Sha1::Sha1() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
mbedtls_sha1_context *ctx = new mbedtls_sha1_context();
this->inner = ctx;
mbedtls_sha1_init(ctx);
#endif
}
bool Sha1::Start() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha1_starts(ctx);
return true;
#endif
return false;
}
bool Sha1::Update(const uint8_t *buffer, size_t sz) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha1_update(ctx, buffer, sz);
return true;
#endif
return false;
}
bool Sha1::Update(std::shared_ptr strm) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
if (strm == nullptr)
return false;
uint8_t buffer[1024];
size_t read;
do {
read = strm->Read(buffer, sizeof(buffer));
if (!Update(buffer, read))
return false;
} while (read != 0);
return true;
#endif
return false;
}
std::vector Sha1::Finish() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
std::vector hash;
hash.resize(20);
mbedtls_sha1_finish(ctx, hash.data());
return hash;
#endif
return {};
}
Sha1::~Sha1() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha1_free(ctx);
delete ctx;
#endif
}
std::vector Sha1::ComputeHash(const uint8_t *buffer, size_t len) {
Sha1 sha1;
if (!sha1.Start())
return {};
if (!sha1.Update(buffer, len))
return {};
return sha1.Finish();
}
std::vector
Sha1::ComputeHash(std::shared_ptr strm) {
Sha1 sha1;
if (!sha1.Start())
return {};
if (!sha1.Update(strm))
return {};
return sha1.Finish();
}
Sha256::Sha256() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
mbedtls_sha256_context *ctx = new mbedtls_sha256_context();
this->inner = ctx;
mbedtls_sha256_init(ctx);
#endif
}
bool Sha256::Start(bool is224) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
this->is224 = is224;
mbedtls_sha256_starts(ctx, is224);
return true;
#endif
return false;
}
bool Sha256::Is224() { return this->is224; }
bool Sha256::Update(const uint8_t *buffer, size_t sz) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha256_update(ctx, buffer, sz);
return true;
#endif
return false;
}
bool Sha256::Update(std::shared_ptr strm) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
if (strm == nullptr)
return false;
uint8_t buffer[1024];
size_t read;
do {
read = strm->Read(buffer, sizeof(buffer));
if (!Update(buffer, read))
return false;
} while (read != 0);
return true;
#endif
return false;
}
std::vector Sha256::Finish() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
std::vector hash;
hash.resize(32);
mbedtls_sha256_finish(ctx, hash.data());
return hash;
#endif
return {};
}
Sha256::~Sha256() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha256_free(ctx);
delete ctx;
#endif
}
std::vector Sha256::ComputeHash(const uint8_t *buffer, size_t len,
bool is224) {
Sha256 sha256;
if (!sha256.Start(is224))
return {};
if (!sha256.Update(buffer, len))
return {};
return sha256.Finish();
}
std::vector
Sha256::ComputeHash(std::shared_ptr strm,
bool is224) {
Sha256 sha256;
if (!sha256.Start(is224))
return {};
if (!sha256.Update(strm))
return {};
return sha256.Finish();
}
Sha512::Sha512() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
mbedtls_sha512_context *ctx = new mbedtls_sha512_context();
this->inner = ctx;
mbedtls_sha512_init(ctx);
#endif
}
bool Sha512::Start(bool is384) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
this->is384 = is384;
mbedtls_sha512_starts(ctx, is384);
return true;
#endif
return false;
}
bool Sha512::Is384() { return this->is384; }
bool Sha512::Update(const uint8_t *buffer, size_t sz) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha512_update(ctx, buffer, sz);
return true;
#endif
return false;
}
bool Sha512::Update(std::shared_ptr strm) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
if (strm == nullptr)
return false;
uint8_t buffer[1024];
size_t read;
do {
read = strm->Read(buffer, sizeof(buffer));
if (!Update(buffer, read))
return false;
} while (read != 0);
return true;
#endif
return false;
}
std::vector Sha512::Finish() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
std::vector hash;
hash.resize(64);
mbedtls_sha512_finish(ctx, hash.data());
return hash;
#endif
return {};
}
Sha512::~Sha512() {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
auto ctx = static_cast(this->inner);
mbedtls_sha512_free(ctx);
delete ctx;
#endif
}
std::vector Sha512::ComputeHash(const uint8_t *buffer, size_t len,
bool is384) {
Sha512 sha512;
if (!sha512.Start(is384))
return {};
if (!sha512.Update(buffer, len))
return {};
return sha512.Finish();
}
std::vector
Sha512::ComputeHash(std::shared_ptr strm,
bool is384) {
Sha512 sha512;
if (!sha512.Start(is384))
return {};
if (!sha512.Update(strm))
return {};
return sha512.Finish();
}
bool PBKDF2(std::vector &output, std::string pass,
std::vector &salt, long itterations, ShaVersion version) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
const mbedtls_md_info_t *info = NULL;
switch (version) {
case ShaVersion::VERSION_SHA1:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
break;
case ShaVersion::VERSION_SHA224:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA224);
break;
case ShaVersion::VERSION_SHA256:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
break;
default:
case ShaVersion::VERSION_SHA384:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
break;
case ShaVersion::VERSION_SHA512:
info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
break;
}
mbedtls_md_setup(&ctx, info, 1);
if (mbedtls_pkcs5_pbkdf2_hmac(
&ctx, (const unsigned char *)pass.c_str(), pass.size(), salt.data(),
salt.size(), (uint32_t)itterations, (uint32_t)output.size(),
output.data()) == 0) {
mbedtls_md_free(&ctx);
return true;
}
mbedtls_md_free(&ctx);
return false;
#else
return false;
#endif
}
bool RandomBytes(std::vector &output, std::string personal_str) {
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
mbedtls_entropy_context entropy = {0};
mbedtls_ctr_drbg_context ctr_drbg = {0};
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)personal_str.c_str(),
personal_str.size());
if (ret != 0) {
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return false;
}
ret = mbedtls_ctr_drbg_random(&ctr_drbg, output.data(), output.size());
if (ret != 0) {
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return false;
}
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return true;
#endif
return false;
}
bool ConstantEquals(const TF_Span left, const TF_Span right)
{
if (left.size() != right.size()) return false;
if (left.empty()) return true;
const auto* pa = left.data();
const auto* pb = right.data();
const auto n = left.size();
uint8_t diff = 0;
for (size_t i = 0; i < n; i++)
diff |= pa[i] ^ pb[i];
return diff == 0;
}
} // namespace Tesses::Framework::Crypto