湛江网站建设方案报价,如何自己买域做网站,网站中英文切换代码,网站空间试用计算机安全和数据隐私是现代应用程序设计中至关重要的方面。为了确保数据的机密性和完整性#xff0c;常常需要使用加密和解密算法。C是一种广泛使用的编程语言#xff0c;提供了许多加密和解密算法的实现。本文将介绍一些在C中常用的加密与解密算法#xff0c;这其中包括Xo…计算机安全和数据隐私是现代应用程序设计中至关重要的方面。为了确保数据的机密性和完整性常常需要使用加密和解密算法。C是一种广泛使用的编程语言提供了许多加密和解密算法的实现。本文将介绍一些在C中常用的加密与解密算法这其中包括Xor异或、BASE64、AES、MD5、SHA256、RSA等。
异或加解密
异或XOR加密算法是一种基于异或运算的简单且常见的加密技术。在异或加密中每个位上的值通过与一个密钥位进行异或运算来改变。这种加密算法的简单性和高效性使得它在某些场景下很有用尤其是对于简单的数据加密需求。
异或运算是一种逻辑运算其规则如下
0 XOR 0 00 XOR 1 11 XOR 0 11 XOR 1 0
在异或加密中将明文与密钥进行逐位异或运算。如果明文位和密钥位相同则结果为0如果不同则结果为1。这个过程是可逆的即可以通过再次异或同样的密钥来还原原始明文。
#include Windows.h
#include iostreamusing namespace std;// 获取异或整数
long GetXorKey(const char* StrPasswd)
{char cCode[32] { 0 };strcpy(cCode, StrPasswd);DWORD Xor_Key 0;for (unsigned int x 0; x strlen(cCode); x){Xor_Key Xor_Key * 4 cCode[x];}return Xor_Key;
}// 异或为字符串
std::string XorEncrypt(std::string content, std::string secretKey)
{for (UINT i 0; i content.length(); i){content[i] ^ secretKey[i % secretKey.length()];}return content;
}int main(int argc, char* argv[])
{// 计算加密密钥long ref GetXorKey(lyshark);std::cout 计算异或密钥: ref std::endl;// 执行异或加密char szBuffer[1024] hello lyshark;for (int x 0; x strlen(szBuffer); x){szBuffer[x] szBuffer[x] ^ ref;std::cout 加密后: szBuffer[x] std::endl;}// 直接异或字符串std::string xor_string hello lyshark;std::cout 加密后: XorEncrypt(xor_string, lyshark).c_str() std::endl;system(pause);return 0;
}运行后对特定字符串异或处理如下图 BASE64加解密
Base64 是一种常见的编码和解码算法用于将二进制数据转换成可打印的 ASCII 字符串以及将这样的字符串还原回二进制数据。Base64 编码是一种将二进制数据表示为 ASCII 字符的方式广泛应用于数据传输和存储领域。
Base64 编码基于一组 64 个字符的编码表通常包括大写字母 A-Z、小写字母 a-z、数字 0-9以及两个额外的字符 ‘’ 和 ‘/’。这样的字符集是为了确保编码后的数据是可打印的并且在不同系统之间可以被准确传输。
编码的过程如下
将待编码的数据划分为每 3 个字节一组24 位。将每组 3 个字节拆分成 4 个 6 位的块。每个 6 位的块对应编码表中的一个字符。如果数据长度不是 3 的倍数使用 ‘’ 字符进行填充。
解码的过程是编码的逆过程。
#include iostream
#include Windows.h// base64 转换表, 共64个
static const char base64_alphabet[] {A, B, C, D, E, F, G,H, I, J, K, L, M, N,O, P, Q, R, S, T,U, V, W, X, Y, Z,a, b, c, d, e, f, g,h, i, j, k, l, m, n,o, p, q, r, s, t,u, v, w, x, y, z,0, 1, 2, 3, 4, 5, 6, 7, 8, 9,, /
};// 解码时使用
static const unsigned char base64_suffix_map[256] {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255
};static char cmove_bits(unsigned char src, unsigned lnum, unsigned rnum)
{src lnum; // src src lnum;src rnum; // src src rnum;return src;
}int base64_encode(const char* indata, int inlen, char* outdata, int* outlen)
{int ret 0;if (indata NULL || inlen 0){return ret -1;}// 源字符串长度, 如果in_len不是3的倍数, 那么需要补成3的倍数int in_len 0;// 需要补齐的字符个数, 这样只有2, 1, 0(0的话不需要拼接, )int pad_num 0; if (inlen % 3 ! 0){pad_num 3 - inlen % 3;}// 拼接后的长度, 实际编码需要的长度(3的倍数)in_len inlen pad_num;// 编码后的长度int out_len in_len * 8 / 6;// 定义指针指向传出data的首地址char* p outdata;//编码, 长度为调整后的长度, 3字节一组for (int i 0; i in_len; i 3){// 将indata第一个字符向右移动2bit(丢弃2bit)int value *indata 2;// 对应base64转换表的字符char c base64_alphabet[value];// 将对应字符(编码后字符)赋值给outdata第一字节*p c;//处理最后一组(最后3字节)的数据if (i inlen pad_num - 3 pad_num ! 0){if (pad_num 1){*(p 1) base64_alphabet[(int)(cmove_bits(*indata, 6, 2) cmove_bits(*(indata 1), 0, 4))];*(p 2) base64_alphabet[(int)cmove_bits(*(indata 1), 4, 2)];*(p 3) ;}else if (pad_num 2){// 编码后的数据要补两个 *(p 1) base64_alphabet[(int)cmove_bits(*indata, 6, 2)];*(p 2) ;*(p 3) ;}}else{// 处理正常的3字节的数据*(p 1) base64_alphabet[cmove_bits(*indata, 6, 2) cmove_bits(*(indata 1), 0, 4)];*(p 2) base64_alphabet[cmove_bits(*(indata 1), 4, 2) cmove_bits(*(indata 2), 0, 6)];*(p 3) base64_alphabet[*(indata 2) 0x3f];}p 4;indata 3;}if (outlen ! NULL){*outlen out_len;}return ret;
}int base64_decode(const char* indata, int inlen, char* outdata, int* outlen)
{int ret 0;if (indata NULL || inlen 0 || outdata NULL || outlen NULL){return ret -1;}if (inlen % 4 ! 0){// 需要解码的数据不是4字节倍数return ret -2;}int t 0, x 0, y 0, i 0;unsigned char c 0;int g 3;while (indata[x] ! 0){// 需要解码的数据对应的ASCII值对应base64_suffix_map的值c base64_suffix_map[indata[x]];// 对应的值不在转码表中if (c 255)return -1;// 对应的值是换行或者回车if (c 253)continue;if (c 254){// 对应的值是c 0; g--;}// 将其依次放入一个int型中占3字节t (t 6) | c;if (y 4){outdata[i] (unsigned char)((t 16) 0xff);if (g 1) outdata[i] (unsigned char)((t 8) 0xff);if (g 2) outdata[i] (unsigned char)(t 0xff);y t 0;}}if (outlen ! NULL){*outlen i;}return ret;
}int main(int argc, char* argv[])
{char str1[] hello lyshark;char str3[30] { 0 };char str2[30] { 0 };int len 0;base64_encode(str1, (int)strlen(str1), str2, len);printf(加密后: %s 长度: %d\n, str2, len);base64_decode(str2, (int)strlen(str2), str3, len);printf(解密后: %s 长度: %d\n, str3, len);system(pause);return 0;
}运行后对特定字符串base64处理如下图 AES对称加解密
高级加密标准Advanced Encryption StandardAES是一种对称密钥加密算法广泛用于保护敏感数据的机密性。AES 是一种块密码算法支持不同的密钥长度128、192、256 比特并且在安全性和性能之间取得了很好的平衡。
AES 操作在固定大小的数据块上进行每个数据块大小为 128 比特16 字节。AES 使用称为轮rounds的迭代结构来执行加密和解密。轮数取决于密钥长度分别为 10 轮128 比特密钥、12 轮192 比特密钥和 14 轮256 比特密钥。AES可使用16、24或32字节密钥(对应128、192和256位)AES分为ECB和CBC模式处理的数据必须是块大小16的倍数。
AES 的基本加密流程包括以下步骤
密钥扩展Key Expansion 根据输入密钥生成轮密钥用于后续的轮函数。初始轮Initial Round 将明文与第一轮密钥进行逐字节的异或操作。轮运算Rounds 重复执行一系列轮函数每轮包括四个操作字节替代、行移位、列混淆和轮密钥加。最终轮Final Round 在最后一轮中省略列混淆步骤。
AES 的解密过程与加密过程相似但使用的是逆操作如逆字节替代、逆行移位、逆列混淆和逆轮密钥加。
CryptAcquireContext函数用于获取或创建与加密服务提供程序CSP相关联的密码学上下文。这个函数的目的是为了建立与加密服务提供程序相关的密码学上下文使得后续的加密操作可以在这个上下文中进行。
以下是CryptAcquireContext函数的一般格式
BOOL CryptAcquireContext(HCRYPTPROV *phProv,LPCTSTR pszContainer,LPCTSTR pszProvider,DWORD dwProvType,DWORD dwFlags
);phProv: 一个指向HCRYPTPROV类型的指针用于接收密码学上下文的句柄。pszContainer: 字符串指定与密钥集关联的容器名称。可以为NULL表示不使用容器。pszProvider: 字符串指定要使用的CSP的名称。如果为NULL将使用默认的提供程序。dwProvType: 指定CSP的类型。例如PROV_RSA_FULL表示使用RSA算法的提供程序。dwFlags: 指定标志控制函数的行为。例如CRYPT_VERIFYCONTEXT表示验证上下文而不是尝试使用特定的密钥。
CryptCreateHash 函数用于创建一个与密码学上下文相关联的哈希对象。哈希对象可用于计算数据的哈希值常用于数字签名、数据完整性验证等安全操作。
以下是CryptCreateHash函数的一般格式
BOOL CryptCreateHash(HCRYPTPROV hProv,ALG_ID Algid,HCRYPTKEY hKey,DWORD dwFlags,HCRYPTHASH *phHash
);hProv: 与哈希对象关联的密码学上下文的句柄。Algid: 哈希算法的标识例如CALG_MD5表示MD5算法。hKey: 与哈希对象关联的密钥。在哈希计算中通常不需要密钥因此可以将其设为NULL。dwFlags: 控制函数的行为的标志。一般设为0。phHash: 一个指向HCRYPTHASH类型的指针用于接收哈希对象的句柄。
成功调用该函数后phHash将包含一个指向新创建的哈希对象的句柄该对象与指定的密码学上下文和哈希算法相关联。
CryptHashData函数用于将数据添加到哈希对象中从而更新哈希值。它常用于在计算数字签名或验证数据完整性时逐步处理数据块并更新哈希值。
以下是CryptHashData函数的一般格式
BOOL CryptHashData(HCRYPTHASH hHash,const BYTE *pbData,DWORD dwDataLen,DWORD dwFlags
);hHash: 指向哈希对象的句柄。pbData: 指向包含要添加到哈希对象的数据的缓冲区的指针。dwDataLen: 数据缓冲区的字节数。dwFlags: 控制函数的行为的标志。一般设为0。
成功调用后哈希对象的状态将被更新以反映已添加的数据从而计算新的哈希值。这使得可以逐步处理大型数据而不需要将整个数据加载到内存中。
CryptDeriveKey 函数用于从一个密码导出密钥。这个函数通常用于从用户提供的密码生成对称密钥这样就可以用于加密或解密数据。
以下是 CryptDeriveKey 函数的一般格式
BOOL CryptDeriveKey(HCRYPTPROV hProv,ALG_ID Algid,HCRYPTHASH hBaseData,DWORD dwFlags,HCRYPTKEY *phKey
);hProv: 一个有效的 CSPCryptographic Service Provider句柄。Algid: 密钥算法标识符指定要创建的密钥类型。hBaseData: 与密钥生成相关的基本数据的哈希对象的句柄。可以为 NULL。dwFlags: 控制函数的行为的标志。一般设为 0。phKey: 指向 HCRYPTKEY 类型的指针用于接收生成的密钥的句柄。
成功调用后phKey 将包含一个新的密钥句柄可以用于后续的加密和解密操作。密钥的具体属性比如大小由 Algid 参数决定。
CryptEncrypt 函数用于对数据进行加密。这个函数通常用于加密一个数据块例如一个文件或一个消息。
以下是 CryptEncrypt 函数的一般格式
BOOL CryptEncrypt(HCRYPTKEY hKey,HCRYPTHASH hHash,BOOL Final,DWORD dwFlags,BYTE *pbData,DWORD *pdwDataLen,DWORD dwBufLen
);hKey: 用于加密数据的密钥的句柄。hHash: 句柄指定一个哈希对象。对称算法不需要哈希因此可以为 NULL。Final: 指定是否是最后一个数据块。如果是最后一个数据块将设置为 TRUE。dwFlags: 控制函数的行为的标志。一般设为 0。pbData: 指向要加密的数据的指针。pdwDataLen: 指向一个变量用于输入数据的大小输出加密后数据的大小。dwBufLen: 缓冲区的大小。
成功调用后pbData 将包含加密后的数据。pdwDataLen 将包含加密后数据的实际大小。
CryptDecrypt 函数用于对数据进行解密。这个函数通常用于解密一个数据块例如一个文件或一个消息。
以下是 CryptDecrypt 函数的一般格式
BOOL CryptDecrypt(HCRYPTKEY hKey,HCRYPTHASH hHash,BOOL Final,DWORD dwFlags,BYTE *pbData,DWORD *pdwDataLen
);hKey: 用于解密数据的密钥的句柄。hHash: 句柄指定一个哈希对象。对称算法不需要哈希因此可以为 NULL。Final: 指定是否是最后一个数据块。如果是最后一个数据块将设置为 TRUE。dwFlags: 控制函数的行为的标志。一般设为 0。pbData: 指向要解密的数据的指针。pdwDataLen: 指向一个变量用于输入解密前数据的大小输出解密后数据的大小。
成功调用后pbData 将包含解密后的数据。pdwDataLen 将包含解密后数据的实际大小。
#include stdio.h
#include Windows.h// AES加密
BOOL AesEncrypt(BYTE* pPassword, BYTE* pData, DWORD dwDataLength, DWORD dwBufferLength)
{BOOL bRet TRUE;HCRYPTPROV hCryptProv NULL;HCRYPTHASH hCryptHash NULL;HCRYPTKEY hCryptKey NULL;DWORD dwPasswordLength strlen((char*)pPassword);do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);bRet CryptCreateHash(hCryptProv, CALG_MD5, NULL, 0, hCryptHash);bRet CryptHashData(hCryptHash, pPassword, dwPasswordLength, 0);bRet CryptDeriveKey(hCryptProv, CALG_AES_128, hCryptHash, CRYPT_EXPORTABLE, hCryptKey);bRet CryptEncrypt(hCryptKey, NULL, TRUE, 0, pData, dwDataLength, dwBufferLength);} while (FALSE);if (hCryptKey || hCryptHash || hCryptProv){CryptDestroyKey(hCryptKey);CryptDestroyHash(hCryptHash);CryptReleaseContext(hCryptProv, 0);}return bRet;
}// AES解密
BOOL AesDecrypt(BYTE* pPassword, BYTE* pData, DWORD dwDataLength, DWORD dwBufferLength)
{BOOL bRet TRUE;HCRYPTPROV hCryptProv NULL;HCRYPTHASH hCryptHash NULL;HCRYPTKEY hCryptKey NULL;DWORD dwPasswordLength strlen((char*)pPassword);do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);bRet CryptCreateHash(hCryptProv, CALG_MD5, NULL, 0, hCryptHash);bRet CryptHashData(hCryptHash, pPassword, dwPasswordLength, 0);bRet CryptDeriveKey(hCryptProv, CALG_AES_128, hCryptHash, CRYPT_EXPORTABLE, hCryptKey);bRet CryptDecrypt(hCryptKey, NULL, TRUE, 0, pData, dwDataLength);} while (FALSE);if (hCryptKey || hCryptHash || hCryptProv){CryptDestroyKey(hCryptKey);CryptDestroyHash(hCryptHash);CryptReleaseContext(hCryptProv, 0);}return bRet;
}int main(int argc, char* argv[])
{BYTE pData[MAX_PATH] { 0 };DWORD dwDataLength 0;char* Msg (char *)hello lyshark;strcpy((char*)pData, Msg);dwDataLength 1 ::strlen((char*)pData);// AES 加密AesEncrypt((BYTE*)123321, pData, dwDataLength, MAX_PATH);printf(AES 加密长度: %d 加密后: %s \n, dwDataLength, pData);// AES 解密AesDecrypt((BYTE*)123321, pData, dwDataLength, MAX_PATH);printf(AES 解密长度: %d 解密后: %s \n, dwDataLength, pData);system(pause);return 0;
}上述代码运行实现对特定字符串hello lyshark加密并使用密码123321如下图所示 MD5/SHA256单向加解密
MD5Message Digest Algorithm 5是一种广泛使用的哈希函数常用于生成数据的数字签名。MD5 产生的哈希值摘要通常是一个 128 位的十六进制数字通常表示为 32 个字符。尽管 MD5 在过去广泛用于校验文件完整性和生成密码散列但由于其容易受到碰撞攻击的影响现在已被更安全的哈希算法如 SHA-256 取代。
MD5 是一种不可逆的哈希函数其核心原理包括以下几步
填充 对输入数据进行填充使其长度满足 512 位的倍数并在数据尾部附加原始数据长度的二进制表示。初始化 初始化 128 位的缓冲区用于存储中间计算结果。处理块 将填充后的数据按照 512 位的块进行划分每个块进行一系列的运算更新缓冲区。输出 将最终得到的缓冲区内容作为 MD5 的输出。
MD5 的核心操作主要包括四轮循环每轮循环包含 16 次操作。这些操作涉及位运算、逻辑运算和模运算等以及对缓冲区内容的不断更新。
SHA-256Secure Hash Algorithm 256-bit是 SHA-2 家族中的一员是一种广泛使用的密码哈希函数。SHA-256 生成的哈希值长度为 256 位通常以 64 个字符的十六进制字符串表示。SHA-256 在密码学和数据完整性验证中得到广泛应用被认为是一种安全可靠的哈希算法。
SHA-256 的基本原理与 MD5 类似但具有更复杂的设计和更长的输出长度。其核心过程包括以下几个步骤
填充 将输入数据填充到满足 512 位块大小的倍数并在数据尾部添加原始数据长度的二进制表示。初始化 初始化 256 位的缓冲区用于存储中间计算结果。处理块 将填充后的数据按照 512 位的块进行划分每个块进行一系列的运算更新缓冲区。输出 将最终得到的缓冲区内容作为 SHA-256 的输出。
SHA-256 的核心操作包括四轮循环每轮循环包含 64 次操作。这些操作包括位运算、逻辑运算、模运算等以及对缓冲区内容的不断更新。
CryptAcquireContext 函数用于获取密码学上下文句柄。这个函数通常是在进行加密和解密操作之前调用的第一步。
以下是 CryptAcquireContext 函数的一般格式
BOOL CryptAcquireContext(HCRYPTPROV *phProv,LPCTSTR pszContainer,LPCTSTR pszProvider,DWORD dwProvType,DWORD dwFlags
);phProv: 用于接收密码学上下文句柄的指针。pszContainer: 指定密钥容器的名称。可以为 NULL。pszProvider: 指定加密服务提供者的名称。可以为 NULL。dwProvType: 指定提供者类型。常见的类型包括 PROV_RSA_FULL、PROV_RSA_AES 等。dwFlags: 控制函数的行为的标志。通常为 0。
成功调用后phProv 将包含一个密码学上下文句柄该句柄用于后续的加密和解密操作。
CryptGetHashParam 函数用于检索哈希对象的参数。哈希对象是用于计算数据摘要的对象通常在密码学操作中使用。
以下是 CryptGetHashParam 函数的一般格式
BOOL CryptGetHashParam(HCRYPTHASH hHash,DWORD dwParam,BYTE *pbData,DWORD *pdwDataLen,DWORD dwFlags
);hHash: 哈希对象的句柄。dwParam: 指定要检索的参数类型。常见的参数类型包括 HP_HASHVAL获取哈希值和 HP_HASHSIZE获取哈希值的大小等。pbData: 用于接收参数数据的缓冲区。pdwDataLen: 用于指定输入缓冲区的大小并在成功调用后包含实际返回的数据长度。dwFlags: 控制函数的行为的标志。通常为 0。
成功调用后pbData 缓冲区中将包含请求的参数数据。
CryptDestroyHash 函数用于销毁哈希对象。哈希对象是在进行哈希计算时创建的对象使用完毕后需要通过 CryptDestroyHash 来释放相关资源。
以下是 CryptDestroyHash 函数的一般格式
BOOL CryptDestroyHash(HCRYPTHASH hHash
);hHash: 要销毁的哈希对象的句柄。
函数返回一个布尔值表示是否成功销毁哈希对象。如果成功返回 TRUE否则返回 FALSE。
CryptReleaseContext 函数用于释放密码学上下文。密码学上下文是在进行加密或哈希操作时所创建的使用完毕后需要通过 CryptReleaseContext 来释放相关资源。
以下是 CryptReleaseContext 函数的一般格式
BOOL CryptReleaseContext(HCRYPTPROV hProv,DWORD dwFlags
);hProv: 要释放的密码学上下文的句柄。dwFlags: 一组标志通常可以设置为零。
函数返回一个布尔值表示是否成功释放密码学上下文。如果成功返回 TRUE否则返回 FALSE。
这两个算法都是单向加密算法其可以将一段任意字符串压缩为一个唯一常数。
#include stdio.h
#include Windows.hBOOL CalculateHash(BYTE* pData, DWORD dwDataLength, ALG_ID algHashType, BYTE** ppHashData, DWORD* pdwHashDataLength)
{HCRYPTPROV hCryptProv NULL;HCRYPTHASH hCryptHash NULL;BYTE* pHashData NULL;DWORD dwHashDataLength 0;DWORD dwTemp 0;BOOL bRet FALSE;do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);bRet CryptCreateHash(hCryptProv, algHashType, NULL, NULL, hCryptHash);bRet CryptHashData(hCryptHash, pData, dwDataLength, 0);dwTemp sizeof(dwHashDataLength);bRet CryptGetHashParam(hCryptHash, HP_HASHSIZE, (BYTE*)(dwHashDataLength), dwTemp, 0);pHashData new BYTE[dwHashDataLength];RtlZeroMemory(pHashData, dwHashDataLength);bRet ::CryptGetHashParam(hCryptHash, HP_HASHVAL, pHashData, dwHashDataLength, 0);*ppHashData pHashData;*pdwHashDataLength dwHashDataLength;} while (FALSE);if (FALSE bRet){if (pHashData){delete[]pHashData;pHashData NULL;}}if (hCryptHash || hCryptProv){CryptDestroyHash(hCryptHash);CryptReleaseContext(hCryptProv, 0);}return bRet;
}int main(int argc, char* argv[])
{char szBuf[1024] hello lyshark;BYTE* pHashData NULL;DWORD dwHashDataLength 0;// MD5CalculateHash((BYTE *)szBuf, strlen(szBuf), CALG_MD5, pHashData, dwHashDataLength);for (DWORD x 0; x dwHashDataLength; x){printf(%x, pHashData[x]);}printf(\n);// SHA256CalculateHash((BYTE *)szBuf, strlen(szBuf), CALG_SHA_256, pHashData, dwHashDataLength);for (DWORD x 0; x dwHashDataLength; x){printf(%x, pHashData[x]);}delete[]pHashData;pHashData NULL;system(pause);return 0;
}上述代码运行后则可以计算出hello lyshark字符串的md5以及sha256摘要信息如下所示 RSA对称加解密
RSARivest–Shamir–Adleman是一种非对称加密算法于1977年由罗纳德·李维斯特Ron Rivest、阿迪·萨米尔Adi Shamir和伦纳德·阿德曼Leonard Adleman三位密码学家提出。RSA算法基于两个大素数的乘积的难解性问题它广泛用于安全通信和数字签名等领域。
RSA算法涉及到两个密钥公钥和私钥。其中公钥用于加密私钥用于解密。其基本原理建立在两个数论问题上
大整数分解问题 将一个大合数分解为两个质数的乘积的难度。欧拉函数和模反演问题 利用欧拉函数和模反演性质确保仅有私钥的持有者能够有效地解密。
RSA算法的密钥生成过程包括以下步骤
选择两个大素数 p 和 q。计算 n pqn 称为模数。计算欧拉函数 φ(n) (p-1)(q-1)。选择公钥 e满足 1 e φ(n)且 e 与 φ(n) 互质。计算私钥 d使得 de ≡ 1 (mod φ(n))。
公钥是 (n, e)私钥是 (n, d)。
加密和解密过程如下 RSA算法的安全性基于大整数分解问题的困难性即在已知 n 的情况下要找到 p 和 q 的乘积。当 n 非常大时这一过程变得非常耗时使得RSA算法在当前的计算资源下被广泛应用于加密通信和数字签名。
CryptGenKey 是 Windows Cryptographic API (CryptoAPI) 中的一个函数用于生成密钥。该函数允许应用程序生成对称密钥、非对称密钥对以及用于哈希的密钥。
以下是 CryptGenKey 函数的一般格式
BOOL CryptGenKey(HCRYPTPROV hProv,ALG_ID Algid,DWORD dwFlags,HCRYPTKEY *phKey
);hProv: 用于生成密钥的密码学服务提供者 (CSP) 的句柄。Algid: 标识要生成的密钥类型可以是对称密钥算法、非对称密钥算法或用于哈希的密钥算法。dwFlags: 控制密钥生成的标志。对于不同的密钥类型可能有不同的标志。phKey: 生成的密钥的句柄。
函数返回一个布尔值表示是否成功生成密钥。如果成功返回 TRUE否则返回 FALSE。
CryptExportKey 函数是 Windows Cryptographic API (CryptoAPI) 中的一个函数用于导出密钥的原始或简单 BLOB 格式。密钥 BLOB 包含密钥的完整信息以便在不同的系统或进程之间传输密钥。
以下是 CryptExportKey 函数的一般格式
BOOL CryptExportKey(HCRYPTKEY hKey,HCRYPTKEY hExpKey,DWORD dwBlobType,DWORD dwFlags,BYTE *pbData,DWORD *pdwDataLen
);hKey: 要导出的密钥的句柄。hExpKey: 导出密钥的密码学服务提供者 (CSP) 句柄。通常使用与 hKey 相同的 CSP。dwBlobType: 导出的 BLOB 类型可以是简单 BLOB 或原始 BLOB。dwFlags: 导出操作的标志。pbData: 用于接收导出的密钥 BLOB 的缓冲区。pdwDataLen: 指向存储密钥 BLOB 大小的变量的指针。在调用函数之前应将其设置为缓冲区的大小在调用函数后它将包含实际写入缓冲区的字节数。
函数返回一个布尔值表示是否成功导出密钥。如果成功返回 TRUE否则返回 FALSE。
CryptImportKey 函数是 Windows Cryptographic API (CryptoAPI) 中的一个函数用于导入密钥的原始或简单 BLOB 格式。该函数通常与 CryptExportKey 函数一起使用用于在不同的系统或进程之间传输密钥。
以下是 CryptImportKey 函数的一般格式
BOOL CryptImportKey(HCRYPTPROV hProv,const BYTE *pbData,DWORD dwDataLen,HCRYPTKEY hPubKey,DWORD dwFlags,HCRYPTKEY *phKey
);hProv: 密钥将与之关联的密码学服务提供者 (CSP) 的句柄。pbData: 包含要导入的密钥 BLOB 的缓冲区的指针。dwDataLen: 密钥 BLOB 的长度以字节为单位。hPubKey: 用于解密密钥 BLOB 的公钥的句柄。dwFlags: 导入密钥的标志。phKey: 指向导入的密钥的句柄的指针。
函数返回一个布尔值表示是否成功导入密钥。如果成功返回 TRUE否则返回 FALSE。
RSA算法包括公钥与私钥两部加密时会先使用RSA生成公钥与私钥然后在进行加密。
#include iostream
#include Windows.husing namespace std;// 生成公钥和私钥
BOOL GenerateKey(BYTE **ppPublicKey, DWORD *pdwPublicKeyLength, BYTE **ppPrivateKey, DWORD *pdwPrivateKeyLength)
{BOOL bRet TRUE;HCRYPTPROV hCryptProv NULL;HCRYPTKEY hCryptKey NULL;BYTE *pPublicKey NULL;DWORD dwPublicKeyLength 0;BYTE *pPrivateKey NULL;DWORD dwPrivateKeyLength 0;do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);if (FALSE bRet)break;bRet CryptGenKey(hCryptProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, hCryptKey);if (FALSE bRet)break;bRet CryptExportKey(hCryptKey, NULL, PUBLICKEYBLOB, 0, NULL, dwPublicKeyLength);if (FALSE bRet)break;pPublicKey new BYTE[dwPublicKeyLength];RtlZeroMemory(pPublicKey, dwPublicKeyLength);bRet CryptExportKey(hCryptKey, NULL, PUBLICKEYBLOB, 0, pPublicKey, dwPublicKeyLength);if (FALSE bRet)break;bRet CryptExportKey(hCryptKey, NULL, PRIVATEKEYBLOB, 0, NULL, dwPrivateKeyLength);if (FALSE bRet)break;pPrivateKey new BYTE[dwPrivateKeyLength];RtlZeroMemory(pPrivateKey, dwPrivateKeyLength);bRet CryptExportKey(hCryptKey, NULL, PRIVATEKEYBLOB, 0, pPrivateKey, dwPrivateKeyLength);if (FALSE bRet)break;*ppPublicKey pPublicKey;*pdwPublicKeyLength dwPublicKeyLength;*ppPrivateKey pPrivateKey;*pdwPrivateKeyLength dwPrivateKeyLength;} while (FALSE);if (hCryptKey)CryptDestroyKey(hCryptKey);if (hCryptProv)CryptReleaseContext(hCryptProv, 0);return bRet;
}// 公钥加密数据
BOOL RsaEncrypt(BYTE *pPublicKey, DWORD dwPublicKeyLength, BYTE *pData, DWORD dwDataLength, DWORD dwBufferLength)
{BOOL bRet TRUE;HCRYPTPROV hCryptProv NULL;HCRYPTKEY hCryptKey NULL;do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);if (FALSE bRet)break;bRet CryptImportKey(hCryptProv, pPublicKey, dwPublicKeyLength, NULL, 0, hCryptKey);if (FALSE bRet)break;bRet CryptEncrypt(hCryptKey, NULL, TRUE, 0, pData, dwDataLength, dwBufferLength);if (FALSE bRet)break;} while (FALSE);if (hCryptKey)CryptDestroyKey(hCryptKey);if (hCryptProv)CryptReleaseContext(hCryptProv, 0);return bRet;
}// 私钥解密数据
BOOL RsaDecrypt(BYTE *pPrivateKey, DWORD dwProvateKeyLength, BYTE *pData, DWORD dwDataLength)
{BOOL bRet TRUE;HCRYPTPROV hCryptProv NULL;HCRYPTKEY hCryptKey NULL;do{bRet CryptAcquireContext(hCryptProv, NULL, NULL, PROV_RSA_FULL, 0);if (FALSE bRet)break;bRet CryptImportKey(hCryptProv, pPrivateKey, dwProvateKeyLength, NULL, 0, hCryptKey);if (FALSE bRet)break;bRet CryptDecrypt(hCryptKey, NULL, TRUE, 0, pData, dwDataLength);if (FALSE bRet)break;} while (FALSE);if (hCryptKey)CryptDestroyKey(hCryptKey);if (hCryptProv)CryptReleaseContext(hCryptProv, 0);return bRet;
}int main(int argc, char * argv[])
{BYTE *pPublicKey NULL;DWORD dwPublicKeyLength 0;BYTE *pPrivateKey NULL;DWORD dwPrivateKeyLength 0;BYTE *pData NULL;DWORD dwDataLength 0;DWORD dwBufferLength 4096;pData new BYTE[dwBufferLength];RtlZeroMemory(pData, dwBufferLength);lstrcpy((char *)pData, hello lyshark);dwDataLength 1 lstrlen((char *)pData);// 输出加密前原始数据printf(加密前原始数据: );for (int i 0; i dwDataLength; i)printf(%x, pData[i]);printf(\n\n);// 生成公钥和私钥GenerateKey(pPublicKey, dwPublicKeyLength, pPrivateKey, dwPrivateKeyLength);printf(公钥: );for (int i 0; i dwPublicKeyLength; i)printf(%.2x, pPublicKey[i]);printf(\n\n);printf(私钥: );for (int i 0; i dwPrivateKeyLength; i)printf(%.2x, pPrivateKey[i]);printf(\n\n);// 使用公钥加密RsaEncrypt(pPublicKey, dwPublicKeyLength, pData, dwDataLength, dwBufferLength);printf(公钥加密: );for (int i 0; i dwDataLength; i)printf(%x, pData[i]);printf(\n\n);// 使用私钥解密RsaDecrypt(pPrivateKey, dwPrivateKeyLength, pData, dwDataLength);printf(私钥解密: );for (int i 0; i dwDataLength; i)printf(%x, pData[i]);printf(\n\n);delete[]pData;delete[]pPrivateKey;delete[]pPublicKey;system(pause);return 0;
}运行后生成公钥与私钥并对字符串加密与解密如下图所示