数据加密解密是一个常用的功能,如果你不希望让别人看到文件中的内容,可以通过密钥(也称”密码“)将文件的内容加密。比如文本文件(.txt),加密前的内容是能够读懂的,加密后的内容是”乱码“,都是一些奇怪的字符,根本无法阅读。
数据加密解密的原理也很简单,就是使用异或运算。请先看下面的代码:
#include<stdio.h>
#include<stdlib.h>
int main()
{
#pragma warning(suppress : 4996)
char plaintext = 'a'; //明文
char secretkey = '!'; //密钥
char ciphertext = plaintext ^ secretkey; //密文
char decodetext = ciphertext ^ secretkey; //解密后的字符
char buffer[9];
printf(" char ASCII\n");
// itoa()用来将数字转换为字符串,可以设定转换时的进制(基数)
// 这里将字符对应的ascii码转换为二进制
printf(" plaintext %c %7s\n", plaintext, itoa(plaintext, buffer, 2));
printf(" secretkey %c %7s\n", secretkey, itoa(secretkey, buffer, 2));
printf("ciphertext %c %7s\n", ciphertext, itoa(ciphertext, buffer, 2));
printf("decodetext %c %7s\n", decodetext, itoa(decodetext, buffer, 2));
return 0;
}
运行结果:
char ASCII
plaintext a 1100001
secretkey ! 100001
ciphertext @ 1000000
decodetext a 1100001
看到了吗,plaintext 与 decodetext相同,也就是说,两次异或运算后还是原来的结果。
这就是加密的关键技术:
1、通过一次异或运算,生成密文,密文没有可读性,与原文风马牛不相及,这就是加密;
2、密文再经过一次异或运算,就会还原成原文,这就是解密的过程;
3、加密和解密需要相同的密钥,如果密钥不对,是无法成功解密的。
上面的加密算法称为对称加密算法,加密和解密使用同一个密钥。
如果加密和解密的密钥不同,则称为非对称加密算法。在非对称算法中,加密的密钥称为公钥,解密的密钥称为私钥,只知道公钥是无法解密的,还必须知道私钥。
注意:程序中的 itoa() 位于 stdlib.h 头文件,它并不是一个标准的C函数,只有Windows下有,
使用异或运算对数据及文件进行加密处理
typedef struct CRYPT_BLOCK
{
DWORD dwSize; // Data的
DWORD dwKey; // 密钥 循环使用DWORD的每个字节来进行加密 详情见XorEncrypt
char chData[1]; // 加密后的数据
} CRYPT_BLOCK, *PCRYPT_BLOCK;
typedef boost::shared_ptr<Json::Value> JsonSharedPtr;
一个数异或另一个数两次后,该数保持不变。即:
c = a^b;
c = c^b;
c == a;
这一规律就是使用异或运算对数据及文件进行加密处理的基本原理。
bool XorEncrypt(const char* pKey, DWORD dwCbKey, const char* pIn, DWORD dwCbSize, char* pOut)
{
if (pIn == NULL || pOut == NULL || pKey == NULL) {
return false;
}
for (DWORD i = 0; i < dwCbSize; ++i) {
pOut[i] = pIn[i] ^ pKey[i % dwCbKey];
}
return true;
}
pKey为密钥数据指针,dwCbKey为密钥数据长度,pIn为需要加密的数据指针,dwCbSize为需要加密的数据长度,pOut为加密后数据指针
加密函数:
vector<char> Encrypt(const vector<char> &vecPlainData)
{
vector<char> vecCryptedData;
do {
if (vecPlainData.empty()) {
break;
}
if (UINT_MAX - vecPlainData.size() < sizeof(CRYPT_BLOCK) - 1) {
//溢出
break;
}
//文件里的加密信息是分成一个一个数据块CRYPT_BLOCK存放的
//只是用异或简单加密一下,具体加密流程见XorEncrypt函数
DWORD dwCryptBlockSize = sizeof(CRYPT_BLOCK) - 1 + vecPlainData.size();
vecCryptedData.resize(dwCryptBlockSize);
PCRYPT_BLOCK CryptedBlock = (PCRYPT_BLOCK)&vecCryptedData[0];
CryptedBlock->dwKey = GenerateKey();
CryptedBlock->dwSize = vecPlainData.size();
bool bOk = XorEncrypt((char*)&CryptedBlock->dwKey, sizeof CryptedBlock->dwKey, &vecPlainData[0], vecPlainData.size(), CryptedBlock->chData);
if (!bOk) {
vecCryptedData.clear();
}
} while (false);
return vecCryptedData;
}
解密函数:
vector<char> Decrypt(const vector<char> &vecCryptedData)
{
PCRYPT_BLOCK pCryptedBlock = NULL;
vector<char> vecPlainData;
do {
if (vecCryptedData.size() < sizeof *pCryptedBlock) {
break;
}
pCryptedBlock = (PCRYPT_BLOCK)&vecCryptedData[0];
if (UINT_MAX - pCryptedBlock->dwSize < sizeof *pCryptedBlock - 1) {
//溢出
break;
}
//运算符优先级 sizeof > 加减 > 不等
if (pCryptedBlock->dwSize + sizeof *pCryptedBlock - 1 != vecCryptedData.size()) {
break;
}
vecPlainData.resize(pCryptedBlock->dwSize);
bool ok = XorEncrypt((char *)&pCryptedBlock->dwKey, sizeof pCryptedBlock->dwKey, pCryptedBlock->chData, pCryptedBlock->dwSize, &vecPlainData[0]);
if (!ok) {
vecPlainData.clear();
}
} while (false);
return vecPlainData;
}
生成Key:
BYTE CHipsLogQueue::RandomByte()
{
unsigned int random;
rand_s(&random);
return BYTE(random);
}
DWORD CHipsLogQueue::GenerateKey()
{
DWORD Key = 0;
for (int i = 0; i < 4; ++i) {
((BYTE *)(&Key))[i] = RandomByte();
}
return Key;
}