Files
2026-09-03 16:18:49 +08:00

292 lines
9.7 KiB
C++

#include "dl_crypto.h"
#include <cstdint>
#include <array>
#include <cassert>
#include <openssl/evp.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include "math/dl_algorithm.h"
#include "memory/dl_code_cvt.h"
#include "io/dl_log.h"
#include "math/dl_random.h"
#include "base/dl_string.h"
// from zlib
extern "C" {
unsigned long crc32(
unsigned long crc,
const unsigned char* buf,
unsigned len);
}
namespace dl::Crypto
{
std::array<uint32_t, 256> map_key = {
0x9f299c37, 0x6685d0d5, 0x79a250a6, 0x28c3077f, 0x683e8b14, 0xeb22ee26, 0x96d41f96, 0x9b8f6bc6,
0xb24396fc, 0xd80c7504, 0x37ac69d8, 0x38c730ec, 0x1741b09f, 0xe0f5c354, 0x5bce7a63, 0x619a64a0,
0xcf50e0f8, 0x65d59573, 0x8dc6e9f8, 0x727de110, 0xed11bf48, 0x56d0f506, 0x18c42a32, 0xa7bcdc53,
0xaf741176, 0x84ba8ffc, 0x6230b121, 0x60c81f34, 0xbb94aeed, 0x67c03614, 0x43620e6a, 0xa44fde40,
0xa271ee1f, 0xf085ec1b, 0x6e89fea0, 0x3f97a87c, 0xb7bfafbf, 0x7a2ab129, 0x6bbd8186, 0x47720465,
0xea82986e, 0x4298cbea, 0x6bf3e229, 0xddae306a, 0x88e42ae6, 0x12f64576, 0xff0f15b3, 0x354765ed,
0x6c51a48b, 0x56c3ed34, 0x23eeef1c, 0x31a85aeb, 0x52f56b70, 0xd195a3fa, 0xc7551d4b, 0x4bed0ed0,
0xff81692a, 0x432fc740, 0xa27fa6a8, 0xfe87c779, 0x89e26fa8, 0xbecd85c6, 0xd989b565, 0xbf01bd0e,
0xfb2f4aac, 0xae57c13f, 0xfd2e359e, 0x56e8b58e, 0xa5768040, 0x16c720e6, 0x3806044c, 0x9436c94d,
0xeabef817, 0x93dccd58, 0x5877b2af, 0x7372744a, 0x7bd5ed87, 0x4aac1851, 0xa24889df, 0x5f801d82,
0x4b24ba4a, 0x5b9344d6, 0xfd90354d, 0xe6d46cee, 0xd57fa9c8, 0x2fc4911c, 0x1f4e86d6, 0x172b0e80,
0xcf08d816, 0xd16ea587, 0x4ae17944, 0x59833ee2, 0x372b5826, 0x227b62f7, 0x3ce4e05f, 0x6c9da58a,
0xd15b8e3d, 0x5d2dbf7e, 0xd1be90b3, 0x8c85937e, 0xf7667a99, 0xc45b8213, 0x84a67c8d, 0x2f1e179a,
0x8ab4fc3e, 0x5a9990fb, 0x7f4804f1, 0x6982f623, 0x74dc03cd, 0x73f09862, 0xd66a9144, 0xca131ee0,
0x4c508b6c, 0x390aa6ee, 0xeb770f95, 0xb38ce227, 0x16905d25, 0x6dcf7144, 0x1535fc14, 0x1acec609,
0xb09f4b1a, 0x976bc982, 0xc466d775, 0x2367d1b9, 0xad1ba63b, 0x7183cd80, 0xcaed4522, 0xab507e3c,
0x98380421, 0xe27e07a9, 0xee0440a5, 0x1e7bf20b, 0xa78777a5, 0xc51ae078, 0x52ce070b, 0x795bbca5,
0x7dece403, 0xec909392, 0xf29b2458, 0xad438632, 0xdcf0221e, 0xf974fe28, 0x524cbd84, 0x9acd29c9,
0x24ac6a41, 0xfa2bd044, 0x3e62e11f, 0x22ab31ee, 0xf87d92c5, 0xcc18ea9d, 0x1a1ea78d, 0xc8dcb329,
0x33bb5b50, 0x67842bc2, 0x123003cf, 0xdc2660df, 0x83f79444, 0xb0635410, 0xeca6e99a, 0x95545781,
0x5a73aaa3, 0x5ff43d74, 0x3fb16726, 0xb16f238f, 0xbceaff33, 0x749836df, 0xf3ef6ca4, 0x1a9d8cb0,
0x28357201, 0x8a2dba74, 0xb0d30faa, 0x509539b8, 0xf6893bdd, 0xcd8ba47c, 0x689b8b71, 0xc3883b23,
0xa8efd5de, 0x9aa1869b, 0x8633837f, 0xd7838010, 0x6be9ed01, 0xbf7ea8af, 0xf0f427f1, 0xa9c8ac00,
0x4b76abfb, 0x182428f3, 0xee2bebd8, 0xe476369c, 0x63a6d323, 0xcc6459d0, 0xa5147a81, 0xefe9d0d4,
0xca3df385, 0xf40a34ce, 0x2bc7db4e, 0xa3e93419, 0x2f81e4d9, 0xe64c380a, 0x7126a0f4, 0x3cfe8d14,
0x4bd3716c, 0xa8be4b61, 0xfb9ce811, 0x2f2628ae, 0xdb9dfa51, 0xe5450719, 0xe0ce127b, 0x8aef9dab,
0xa64d09cf, 0x4fe6bafd, 0x70c77a61, 0x2235991b, 0x552b5b10, 0x73fa93d0, 0x5b7a6efe, 0x3f3eab5b,
0x57956170, 0xf17bffb9, 0x941a12b9, 0x5011ea85, 0xeb8e44b0, 0x480cdd7d, 0x46e79154, 0xa5ba0285,
0x7bf9f6e6, 0x6e0f4193, 0xb50d33e6, 0x1b60470b, 0xa08a9192, 0x784146cc, 0xc1e8f223, 0xc490044d,
0x24592f14, 0x16b3062b, 0x875b5a0b, 0xeee3dea0, 0x8c39eaeb, 0xf62166ea, 0x9cc9f658, 0x8cec8240,
0xc8bcf0f0, 0xc7591af0, 0xd2737c1a, 0xa78e5510, 0x6af2dae4, 0x8278abd7, 0xbfcaefc4, 0x8090f3aa,
0x4ce5a4d7, 0x26263fa4, 0xc48b59b3, 0x45089f72, 0x42cb7e66, 0x369827bf, 0xe3ffb83b, 0x1cb82ad1,
};
void EncryptXor(BufferView buf)
{
size_t num = buf.size() / 20;
size_t tail = buf.size() % 20;
unsigned char* p = (unsigned char*)buf.data();
for (size_t i = 0; i < num; ++i)
{
*(uint32_t*)(p + 0) ^= map_key[i % 256];
*(uint32_t*)(p + 4) ^= map_key[*(p + 0)];
*(uint32_t*)(p + 8) ^= map_key[*(p + 1)];
*(uint32_t*)(p + 12) ^= map_key[*(p + 2)];
*(uint32_t*)(p + 16) ^= map_key[*(p + 3)];
p += 20;
}
for (size_t i = 0; i < tail; ++i)
*(p + i) ^= i;
}
void DecryptXor(BufferView buf)
{
size_t num = buf.size() / 20;
size_t tail = buf.size() % 20;
unsigned char* p = (unsigned char*)buf.data();
for (size_t i = 0; i < num; ++i)
{
*(uint32_t*)(p + 4) ^= map_key[*(p + 0)];
*(uint32_t*)(p + 8) ^= map_key[*(p + 1)];
*(uint32_t*)(p + 12) ^= map_key[*(p + 2)];
*(uint32_t*)(p + 16) ^= map_key[*(p + 3)];
*(uint32_t*)(p + 0) ^= map_key[i % 256];
p += 20;
}
for (size_t i = 0; i < tail; ++i)
*(p + i) ^= i;
}
static std::wstring g_HAN256_TABLE =
L"〇一二三四五六七八九十百千万亿兆"
L"零壹贰叁肆伍陆柒捌玖拾佰仟阴阳中"
L"天子丑寅卯辰巳午未申酉戌亥年月日"
L"无甲乙丙丁戊己庚辛壬癸木火土金水"
L"地正杏桃槐榴荷瓜桂菊露葭腊春夏秋"
L"冬上下乾兑离震巽坎艮坤泰华衡恒嵩"
L"人鼠牛虎兔龙蛇马羊猴鸡狗猪礼乐射"
L"御书数琴棋書画诗酒花茶角徵宫商羽"
L"东蛟亢氐房狐尾箕南井鬼柳星张翼轸"
L"西奎娄胃昴毕觜参北斗牵女虚危室壁"
L"代禹殷周秦汉晋隋唐宋元明清古今来"
L"州隶兖青豫徐冀幽并扬荆益凉交分合"
L"族壮回满维苗彝家藏蒙侗布瑶白朝哈"
L"身肝心脾肾肺筋脉肉皮骨目舌口鼻耳"
L"感怒喜思悲恐风热湿燥寒酸苦甘辣咸"
L"行呼笑歌哭呻碧赤黄缟黑色味触香声";
std::wstring EncodeHan256(BufferView buf)
{
assert(find_equal(g_HAN256_TABLE) == g_HAN256_TABLE.end());
std::wstring ret;
for (auto& iter : buf)
{
ret.push_back(g_HAN256_TABLE[(size_t)iter]);
}
return ret;
}
bool DecodeHan256(const std::wstring& str, Buffer& buf)
{
assert(find_equal(g_HAN256_TABLE) == g_HAN256_TABLE.end());
buf.resize(str.size());
for (size_t i = 0; i < str.size(); ++i)
{
auto iter = g_HAN256_TABLE.find(str[i]);
if (iter == std::wstring::npos)
{
std::wstring str_log = L"不是有效的Han256编码:";
str_log += str[i];
for (size_t i = 0; i < g_HAN256_TABLE.size(); ++i)
{
if (i % 16 == 0)
str_log.push_back(L'\n');
str_log.push_back(g_HAN256_TABLE[i]);
}
log_warn0(CodeCvt::WideCharToUtf8(str_log));
buf.clear();
return false;
}
((std::byte*)buf.data())[i] = (std::byte)iter;
}
return true;
}
uint32_t HashCrc32(BufferView buf, uint32_t crc)
{
return crc32((unsigned long)crc, (const unsigned char*)buf.data(), (unsigned)buf.size());
}
std::string EncodeBase64(BufferView buf)
{
size_t base64_len = (buf.size() + 2) / 3 * 4;
if (base64_len == 0)
return {};
std::string ret;
ret.resize(base64_len);
EVP_EncodeBlock((unsigned char*)ret.data(), (unsigned char*)buf.data(), (int)buf.size());
return ret;
}
bool DecodeBase64(std::string_view str, Buffer& buf)
{
size_t n = str.size();
if (n % 4 != 0)
return false;
buf.resize(n / 4 * 3);
int ret = EVP_DecodeBlock((unsigned char*)buf.data(), (unsigned char*)str.data(), (int)str.size());
if (ret == -1)
{
log_warn("解码失败!");
buf.clear();
return false;
}
// EVP_DecodeBlock 返回值包含 padding 字节,按 '=' 数量减去
size_t num_pad = 0;
if (n > 0 && str[n - 1] == '=')
num_pad++;
if (n > 1 && str[n - 2] == '=')
num_pad++;
buf.resize((size_t)ret - num_pad);
return true;
}
Buffer HashMd5(BufferView buf)
{
Buffer ret{ 16 };
MD5((unsigned char*)buf.data(), buf.size(), (unsigned char*)ret.data());
return ret;
}
Buffer HashSha256(BufferView buf)
{
Buffer ret{ 32 };
SHA256((unsigned char*)buf.data(), buf.size(), (unsigned char*)ret.data());
return ret;
}
Buffer HashSha512(BufferView buf)
{
Buffer ret{ 64 };
SHA512((unsigned char*)buf.data(), buf.size(), (unsigned char*)ret.data());
return ret;
}
Buffer HashBlake2b(BufferView buf)
{
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
if (!ctx)
return {};
const EVP_MD* md = EVP_blake2b512();
if (!EVP_DigestInit_ex(ctx, md, NULL))
{
EVP_MD_CTX_free(ctx);
return {};
}
EVP_DigestUpdate(ctx, buf.data(), buf.size());
unsigned int hash_len;
Buffer ret{ 64 };
EVP_DigestFinal_ex(ctx, (unsigned char*)ret.data(), &hash_len);
assert(hash_len == ret.size());
EVP_MD_CTX_free(ctx);
return ret;
}
dl::Crypto::Aes256Key GenerateKeyAes256()
{
Aes256Key ret;
ret._key = Random::BufferX(32);
ret._iv = Random::BufferX(12);
ret._tag = Random::BufferX(16);
//std::string str = dl::to_string_hex(ret._key);
return ret;
}
dl::Buffer EncryptAes256(BufferView buf, const Aes256Key& key)
{
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)key._iv.size(), nullptr);
EVP_EncryptInit_ex(ctx, nullptr, nullptr,
(unsigned char*)key._key.data(), (unsigned char*)key._iv.data());
Buffer cipher = CreateBuffer(buf);
int len;
EVP_EncryptUpdate(ctx, (unsigned char*)cipher.data(), &len, (unsigned char*)buf.data(), (int)buf.size());
EVP_EncryptFinal_ex(ctx, (unsigned char*)cipher.data() + len, &len);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, (int)key._tag.size(), (void*)key._tag.data());
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
dl::Buffer DecryptAes256(BufferView buf, const Aes256Key& key)
{
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)key._iv.size(), nullptr);
EVP_DecryptInit_ex(ctx, nullptr, nullptr,
(unsigned char*)key._key.data(), (unsigned char*)key._iv.data());
Buffer cipher = CreateBuffer(buf);
int len;
EVP_DecryptUpdate(ctx, (unsigned char*)cipher.data(), &len, (unsigned char*)buf.data(), (int)buf.size());
EVP_DecryptFinal_ex(ctx, (unsigned char*)cipher.data() + len, &len);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, (int)key._tag.size(), (void*)key._tag.data());
EVP_CIPHER_CTX_free(ctx);
return cipher;
}
}