基于Crypto++库的AES对称加密实现对数据的加解密

Carewhose

发布日期: 2018-12-20 12:25:40 浏览量: 1820
评分:
star star star star star star star star star_border star_border
*转载请注明来自write-bug.com

背景

写了一个基于Crypto++加密库中AES对称加密算法实现的对数据加密和解密的一个小程序,Crypto++加密库就不详细介绍了,这个库提供了很多知名的加解密算法,直接调用就好了,使用起来还是比较方便的。

写这篇文章,就是分享自己的学习心得。自己的密码学部分的知识学得不怎么好,还好有Crypto++开源库可以使用,弥补了对加解密部分的不足。现在,向大家分享使用Crypto++中的AES对称加密算法实现对数据的加密解密方面的知识。

程序编译设置注意事项

首先,先要下载Crypto++库的开源代码,然后,自己编译得到Crypto++的库文件。下载链接还有具体的编译步骤,可以参考平台上其他用户写的分享文章“使用VS2013编译Crypto++加密库”,里面有详细介绍。

在导入Crypto++的库文件到自己的工程项目的时候,要对自己的工程项目进行编译设置。主要一点就是:项目工程的属性中的“运行库”设置,要与编译Crypto++的库文件时设置的“运行库”选项要对应一致,否则程序会编译不过的。也就是要检查LIB库工程和本测试工程的:属性 —> C/C++ —> 代码生成 —> 运行库 是否统一。

如果编译出错,报告XX重复定义等错误,同样,要检查LIB库工程和本测试工程的:属性 —> C/C++ —> 代码生成 —> 运行库 是否统一。

程序设计原理

1. AES加密原理

AES对称加密就是对16byte(128bit)数据进行加密的过程,也就是把这128位数据通过一系列的变化变成另一个128位数据。

由于,我们加密的数据大小长度都是未知的,也不都是128位数据对齐。所以,在加密过程的时候,要对自己的数据进行填充,以128位大小对齐,本文的例子是以0作为填充数填充的。

加密实现的核心部分,即使用Crypto++库中提供的AES加密器 AESEncryption 来进行实现的。数据加密主要分成三个步骤:

  • 声明AES加密器

  • 设置AES加密密钥

  • 对数据进行加密,返回加密结果

  1. // 声明AES加密器
  2. AESEncryption aesEncryptor;
  3. …(省略)
  4. // 设置AES加密密钥
  5. aesEncryptor.SetKey(pAESKey, dwAESKeySize);
  6. …(省略)
  7. // 对数据进行加密,返回加密结果
  8. aesEncryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
  9. …(省略)

对于本文介绍的程序,它可以对任意数据长度的数据进行加密,所以,和上面介绍的加密步骤相比,会多两个步骤:

  • 声明AES加密器

  • 将加密数据用0填充,按128位大小进行对齐

  • 设置AES加密密钥

  • 获取128位数据,并对数据进行加密,返回128位加密结果

  • 继续获取下一个128位数据,重复第 4 步操作,直到数据获取完毕

2. AES解密原理

解密部分的原理和加密部分原理是一样的,因为AES是对称加密,所以原理相同。

解密实现的核心部分,即使用Crypto++库中提供的AES解密器 AESDecryption来进行实现的。数据加密主要分成三个步骤:

  • 声明AES加密器

  • 设置AES加密密钥

  • 对数据进行加密,返回加密结果

  1. // 声明AES解密器
  2. AESDecryption aesDecryptor;
  3. …(省略)
  4. // 设置AES解密密钥
  5. aesDecryptor.SetKey(pAESKey, dwAESKeySize);
  6. …(省略)
  7. // 对数据进行解密,返回解密结果
  8. aesDecryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
  9. …(省略)

理论上,解密的密文长度是按128位长度对齐的。但是,为了程序容错性更好,所以,在解密之前,还是和加密一样,先对解密的数据以0填充,按128位数据大小对齐。如果输入的密文长度正确,那么做这一步操作是不影响的;如果输入的密文长度不正确,那么这一步操作可以确保程序不出现错误。

那么,解密部分的解密流程和加密流程是一样的:

  • 声明AES解密器

  • 将解密数据用0填充,按128位大小进行对齐

  • 设置AES解密密钥

  • 获取128位数据,并对数据进行解密,返回128位解密结果

  • 继续获取下一个128位数据,重复第 4 步操作,直到数据获取完毕

编程实现

1. 导入Crypto++库文件

  1. //*************************************************
  2. // crypt++加密库的头文件和静态库
  3. //*************************************************
  4. #include "crypt\\include\\aes.h"
  5. using namespace CryptoPP; // 命名空间
  6. #ifdef _DEBUG
  7. #ifdef _WIN64
  8. #pragma comment(lib, "crypt\\lib\\x64\\debug\\cryptlib.lib")
  9. #else
  10. #pragma comment(lib, "crypt\\lib\\x86\\debug\\cryptlib.lib")
  11. #endif
  12. #else
  13. #ifdef _WIN64
  14. #pragma comment(lib, "crypt\\lib\\x64\\release\\cryptlib.lib")
  15. #else
  16. #pragma comment(lib, "crypt\\lib\\x86\\release\\cryptlib.lib")
  17. #endif
  18. #endif
  19. //*************************************************

2. AES加密实现

  1. // 加密
  2. // 输入:原文内容、原文内容长度、密钥内容、密钥内容长度
  3. // 输出:密文内容、密文内容长度
  4. BOOL AES_Encrypt(BYTE *pOriginalData, DWORD dwOriginalDataSize, BYTE *pAESKey, DWORD dwAESKeySize, BYTE **ppEncryptData, DWORD *pdwEncryptData)
  5. {
  6. // 加密器
  7. AESEncryption aesEncryptor;
  8. // 加密原文数据块
  9. unsigned char inBlock[AES::BLOCKSIZE];
  10. // 加密后密文数据块
  11. unsigned char outBlock[AES::BLOCKSIZE];
  12. // 必须设定全为0
  13. unsigned char xorBlock[AES::BLOCKSIZE];
  14. DWORD dwOffset = 0;
  15. BYTE *pEncryptData = NULL;
  16. DWORD dwEncryptDataSize = 0;
  17. // 计算原文长度, 并按 128位 即 16字节 对齐, 不够则 填充0 对齐
  18. // 商
  19. DWORD dwQuotient = dwOriginalDataSize / AES::BLOCKSIZE;
  20. // 余数
  21. DWORD dwRemaind = dwOriginalDataSize % AES::BLOCKSIZE;
  22. if (0 != dwRemaind)
  23. {
  24. dwQuotient++;
  25. }
  26. // 申请动态内存
  27. dwEncryptDataSize = dwQuotient * AES::BLOCKSIZE;
  28. pEncryptData = new BYTE[dwEncryptDataSize];
  29. if (NULL == pEncryptData)
  30. {
  31. return FALSE;
  32. }
  33. // 设置密钥
  34. aesEncryptor.SetKey(pAESKey, dwAESKeySize);
  35. do
  36. {
  37. // 置零
  38. ::RtlZeroMemory(inBlock, AES::BLOCKSIZE);
  39. ::RtlZeroMemory(xorBlock, AES::BLOCKSIZE);
  40. ::RtlZeroMemory(outBlock, AES::BLOCKSIZE);
  41. // 获取加密块
  42. if (dwOffset <= (dwOriginalDataSize - AES::BLOCKSIZE))
  43. {
  44. ::RtlCopyMemory(inBlock, (PVOID)(pOriginalData + dwOffset), AES::BLOCKSIZE);
  45. }
  46. else
  47. {
  48. ::RtlCopyMemory(inBlock, (PVOID)(pOriginalData + dwOffset), (dwOriginalDataSize - dwOffset));
  49. }
  50. // 加密
  51. aesEncryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
  52. // 构造
  53. ::RtlCopyMemory((PVOID)(pEncryptData + dwOffset), outBlock, AES::BLOCKSIZE);
  54. // 更新数据
  55. dwOffset = dwOffset + AES::BLOCKSIZE;
  56. dwQuotient--;
  57. } while (0 < dwQuotient);
  58. // 返回数据
  59. *ppEncryptData = pEncryptData;
  60. *pdwEncryptData = dwEncryptDataSize;
  61. return TRUE;
  62. }

3. AES解密实现

  1. // 解密
  2. // 输入:密文内容、密文内容长度、密钥内容、密钥内容长度
  3. // 输出:解密后明文内容、解密后明文内容长度
  4. BOOL AES_Decrypt(BYTE *pEncryptData, DWORD dwEncryptData, BYTE *pAESKey, DWORD dwAESKeySize, BYTE **ppDecryptData, DWORD *pdwDecryptData)
  5. {
  6. // 解密器
  7. AESDecryption aesDecryptor;
  8. // 解密密文数据块
  9. unsigned char inBlock[AES::BLOCKSIZE];
  10. // 解密后后明文数据块
  11. unsigned char outBlock[AES::BLOCKSIZE];
  12. // 必须设定全为0
  13. unsigned char xorBlock[AES::BLOCKSIZE];
  14. DWORD dwOffset = 0;
  15. BYTE *pDecryptData = NULL;
  16. DWORD dwDecryptDataSize = 0;
  17. // 计算密文长度, 并按 128位 即 16字节 对齐, 不够则填充0对齐
  18. // 商
  19. DWORD dwQuotient = dwEncryptData / AES::BLOCKSIZE;
  20. // 余数
  21. DWORD dwRemaind = dwEncryptData % AES::BLOCKSIZE;
  22. if (0 != dwRemaind)
  23. {
  24. dwQuotient++;
  25. }
  26. // 申请动态内存
  27. dwDecryptDataSize = dwQuotient * AES::BLOCKSIZE;
  28. pDecryptData = new BYTE[dwDecryptDataSize];
  29. if (NULL == pDecryptData)
  30. {
  31. return FALSE;
  32. }
  33. // 设置密钥
  34. aesDecryptor.SetKey(pAESKey, dwAESKeySize);
  35. do
  36. {
  37. // 置零
  38. ::RtlZeroMemory(inBlock, AES::BLOCKSIZE);
  39. ::RtlZeroMemory(xorBlock, AES::BLOCKSIZE);
  40. ::RtlZeroMemory(outBlock, AES::BLOCKSIZE);
  41. // 获取解密块
  42. if (dwOffset <= (dwDecryptDataSize - AES::BLOCKSIZE))
  43. {
  44. ::RtlCopyMemory(inBlock, (PVOID)(pEncryptData + dwOffset), AES::BLOCKSIZE);
  45. }
  46. else
  47. {
  48. ::RtlCopyMemory(inBlock, (PVOID)(pEncryptData + dwOffset), (dwEncryptData - dwOffset));
  49. }
  50. // 解密
  51. aesDecryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
  52. // 构造
  53. ::RtlCopyMemory((PVOID)(pDecryptData + dwOffset), outBlock, AES::BLOCKSIZE);
  54. // 更新数据
  55. dwOffset = dwOffset + AES::BLOCKSIZE;
  56. dwQuotient--;
  57. } while (0 < dwQuotient);
  58. // 返回数据
  59. *ppDecryptData = pDecryptData;
  60. *pdwDecryptData = dwDecryptDataSize;
  61. return TRUE;
  62. }

程序测试

我们在main函数中,调用上面封装好的加解密函数,对数据进行加解密进行测试。main函数为:

  1. int _tmain(int argc, _TCHAR* argv[])
  2. {
  3. BYTE *pEncryptData = NULL;
  4. DWORD dwEncryptDataSize = 0;
  5. BYTE *pDecryptData = NULL;
  6. DWORD dwDecryptDataSize = 0;
  7. char szOriginalData[] = "CDIY - www.coderdiy.com - 专注计算机技术交流分享";
  8. char szAESKey[] = "DemonGanDemonGan";
  9. BOOL bRet = FALSE;
  10. // 加密
  11. bRet = AES_Encrypt((BYTE *)szOriginalData, (1 + ::lstrlen(szOriginalData)), (BYTE *)szAESKey, ::lstrlen(szAESKey), &pEncryptData, &dwEncryptDataSize);
  12. if (FALSE == bRet)
  13. {
  14. return 1;
  15. }
  16. // 解密
  17. bRet = AES_Decrypt(pEncryptData, dwEncryptDataSize, (BYTE *)szAESKey, ::lstrlen(szAESKey), &pDecryptData, &dwDecryptDataSize);
  18. if (FALSE == bRet)
  19. {
  20. return 2;
  21. }
  22. // 显示
  23. printf("原文数据:\n");
  24. ShowData((BYTE *)szOriginalData, (1 + ::lstrlen(szOriginalData)));
  25. printf("密文数据:\n");
  26. ShowData(pEncryptData, dwEncryptDataSize);
  27. printf("解密后数据:\n");
  28. ShowData(pDecryptData, dwDecryptDataSize);
  29. // 释放内存
  30. delete[]pEncryptData;
  31. pEncryptData = NULL;
  32. delete[]pDecryptData;
  33. pDecryptData = NULL;
  34. system("pause");
  35. return 0;
  36. }

测试的结果为:

通过上述结果,测试成功。

总结

本身使用Crypto++库中的AES加解密不是很复杂,也容易理解。其中,需要注意一点就是,如果实现对任意长度数据的加密,那么就必须要对数据填充,按128位大小进行对齐,填充的数据任意。

参考

参考自《Windows黑客编程技术详解》一书

上传的附件 cloud_download AES_Test.7z ( 251.25kb, 22次下载 )

发送私信

你总是喊着努力努力,可是又坚持了多久

11
文章数
14
评论数
最近文章
eject