C++ CryptoPP使用AES加解密
Crypto++ (CryptoPP) 是一个用于密码学和加密的 C++ 库。它是一个开源项目,提供了大量的密码学算法和功能,包括对称加密、非对称加密、哈希函数、消息认证码 (MAC)、数字签名等。Crypto++ 的目标是提供高性能和可靠的密码学工具,以满足软件开发中对安全性的需求。
高级加密标准(Advanced Encryption Standard,AES)是一种对称密钥加密标准,用于保护电脑上的敏感数据。AES是由美国国家标准与技术研究院(NIST)于2001年确定的,它取代了过时的数据加密标准(Data Encryption Standard,DES)。
以下是AES加密算法的主要特点和概述:
- 对称密钥算法: AES是一种对称密钥算法,意味着相同的密钥用于加密和解密数据。这就要求通信双方在通信前共享密钥,并确保其保密性。
- 分组密码: AES将明文数据分成固定大小的块(128比特),然后对每个块进行独立的加密。这个固定大小的块称为分组。AES支持多种分组长度,包括128比特、192比特和256比特。
- 轮数: AES加密算法的安全性与其轮数相关。轮数表示对数据块的处理循环次数,不同密钥长度的AES使用不同数量的轮数。通常,128比特密钥使用10轮,192比特密钥使用12轮,256比特密钥使用14轮。
- 密钥长度: AES支持多种密钥长度,包括128比特、192比特和256比特。密钥长度的选择直接影响加密算法的安全性。
- SubBytes、ShiftRows、MixColumns和AddRoundKey: 这些是AES加密算法中的四个主要操作,它们通过多轮迭代来加密数据。SubBytes和ShiftRows引入非线性性,MixColumns和AddRoundKey提供了扩散和混淆。
- 强安全性: AES被广泛认为是一种安全、可靠的加密算法。它经过广泛的密码分析和评估,并且在许多应用中得到了广泛的应用,包括加密通信、文件加密和硬件加密。
总体而言,AES是一种高效、安全且广泛应用的加密算法,适用于多种应用场景。其在加密强度和性能之间取得了良好的平衡,因此成为许多信息安全应用的首选算法。
使用AES算法
AES(Advanced Encryption Standard)广泛应用于保护敏感数据的加密和解密过程。以下是AES算法的概述:
1. 对称加密算法:
AES是一种对称加密算法,这意味着加密和解密都使用相同的密钥。密钥是保护数据安全的关键,因此对称加密算法需要确保密钥的安全分发和管理。
2. 密钥长度:
AES支持不同长度的密钥,包括128位、192位和256位。密钥长度越长,通常意味着更高的安全性,但也可能导致加密和解密的计算成本增加。
3. 块加密算法:
AES是块加密算法,它按照固定大小的数据块(128位)进行加密。加密和解密的过程都是对这些数据块的操作。
4. 加解密过程:
加密:
- 数据分块:将明文分成固定大小的数据块(128位)。
- 初始轮密钥加:将明文和初始密钥进行一次简单的混淆操作。
- 轮加密:通过多轮的替代和置换操作(SubBytes、ShiftRows、MixColumns、AddRoundKey),对数据块进行混淆。
- 最终轮:在最后一轮中,省略MixColumns操作。
- 得到密文。
解密:
- 初始轮密钥解:将密文和初始密钥进行一次简单的混淆操作。
- 轮解密:通过多轮的逆操作(InvSubBytes、InvShiftRows、InvMixColumns、AddRoundKey),对数据块进行逆操作。
- 最终轮:在最后一轮中,省略InvMixColumns操作。
- 得到明文。
5. 使用场景:
AES广泛用于保护敏感数据,如文件、数据库、网络通信等。它是许多安全协议和标准的基础,包括TLS(安全套接层)、IPsec(Internet协议安全)等。
6. 安全性:
AES被广泛接受并认为是安全可靠的加密算法。密钥长度的选择对安全性至关重要,一般建议使用128位、192位或256位的密钥以满足特定安全需求。
总体而言,AES作为一种高效且安全的对称加密算法,在现代加密通信中扮演着重要的角色。AES的使用需要引入头文件#include <aes.h>
其他部分与《C++ 通过CryptoPP计算Hash值》
文章中的头文件引入保持一致。
如下AESEncrypt
是一个使用AES算法进行加密的函数。下面是对函数的主要步骤的注释:
- AES加密对象初始化:
- 创建
AESEncryption
对象用于AES加密。 - 定义AES加密需要的数据块:
inBlock
(输入数据块)、outBlock
(输出数据块)、xorBlock
(异或数据块)。
- 创建
- 计算加密数据块大小:
- 计算需要的加密数据块数量,考虑到原始数据大小可能不是AES块大小的整数倍。
- 分配加密后的数据缓冲区:
- 根据计算得到的加密数据块大小分配内存。
- 设置AES加密密钥:
- 调用
SetKey
函数设置AES加密密钥。
- 调用
- AES加密过程:
- 循环处理原始数据块,每次处理一个AES块大小的数据。
- 将原始数据块拷贝到输入数据块。
- 使用AES算法进行加密。
- 将加密后的数据块拷贝到输出缓冲区。
- 返回加密结果:
- 返回加密后的数据缓冲区和大小。
请注意,在实际使用中,要确保释放了分配的内存,以防止内存泄漏。
BOOL AESEncrypt(BYTE *pOriginalData, DWORD dwOriginalDataSize, BYTE *pAESKey, DWORD dwAESKeySize, BYTE **ppEncryptData, DWORD *pdwEncryptData)
{
// 定义AES加密需要的数据块
AESEncryption aesEncryptor;
// 加密原文数据块
unsigned char inBlock[AES::BLOCKSIZE];
// 加密后密文数据块
unsigned char outBlock[AES::BLOCKSIZE];
// 必须设定全为0
unsigned char xorBlock[AES::BLOCKSIZE];
DWORD dwOffset = 0;
BYTE *pEncryptData = NULL;
DWORD dwEncryptDataSize = 0;
// 计算需要的加密数据块大小, 并按 128位 即 16字节 对齐, 不够则 填充0 对齐
// 商
DWORD dwQuotient = dwOriginalDataSize / AES::BLOCKSIZE;
// 余数
DWORD dwRemaind = dwOriginalDataSize % AES::BLOCKSIZE;
if (0 != dwRemaind)
{
dwQuotient++;
}
// 申请动态内存
dwEncryptDataSize = dwQuotient * AES::BLOCKSIZE;
// 分配加密后的数据缓冲区
pEncryptData = new BYTE[dwEncryptDataSize];
if (NULL == pEncryptData)
{
return FALSE;
}
// 设置AES加密密钥
aesEncryptor.SetKey(pAESKey, dwAESKeySize);
do
{
// 初始化数据块
RtlZeroMemory(inBlock, AES::BLOCKSIZE);
RtlZeroMemory(xorBlock, AES::BLOCKSIZE);
RtlZeroMemory(outBlock, AES::BLOCKSIZE);
// 获取加密块
if (dwOffset <= (dwOriginalDataSize - AES::BLOCKSIZE))
{
RtlCopyMemory(inBlock, (PVOID)(pOriginalData + dwOffset), AES::BLOCKSIZE);
}
else
{
RtlCopyMemory(inBlock, (PVOID)(pOriginalData + dwOffset), (dwOriginalDataSize - dwOffset));
}
// 使用AES算法进行加密
aesEncryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
// 将加密后的数据块拷贝到输出缓冲区
RtlCopyMemory((PVOID)(pEncryptData + dwOffset), outBlock, AES::BLOCKSIZE);
// 更新数据
dwOffset = dwOffset + AES::BLOCKSIZE;
dwQuotient--;
} while (0 < dwQuotient);
// 返回数据
*ppEncryptData = pEncryptData;
*pdwEncryptData = dwEncryptDataSize;
return TRUE;
}
如下AESDecrypt
是一个使用AES算法进行解密的函数。以下是对函数的主要步骤的注释:
- AES解密对象初始化:
- 创建
AESDecryption
对象用于AES解密。 - 定义AES解密需要的数据块:
inBlock
(输入数据块)、outBlock
(输出数据块)、xorBlock
(异或数据块)。
- 创建
- 计算解密数据块大小:
- 计算需要的解密数据块数量,考虑到加密数据大小可能不是AES块大小的整数倍。
- 分配解密后的数据缓冲区:
- 根据计算得到的解密数据块大小分配内存。
- 设置AES解密密钥:
- 调用
SetKey
函数设置AES解密密钥。
- 调用
- AES解密过程:
- 循环处理加密数据块,每次处理一个AES块大小的数据。
- 将加密数据块拷贝到输入数据块。
- 使用AES算法进行解密。
- 将解密后的数据块拷贝到输出缓冲区。
- 返回解密结果:
- 返回解密后的数据缓冲区和大小。
请注意,在实际使用中,要确保释放了分配的内存,以防止内存泄漏。
BOOL AESDecrypt(BYTE *pEncryptData, DWORD dwEncryptData, BYTE *pAESKey, DWORD dwAESKeySize, BYTE **ppDecryptData, DWORD *pdwDecryptData)
{
// 定义AES解密需要的数据块
AESDecryption aesDecryptor;
// 解密密文数据块
unsigned char inBlock[AES::BLOCKSIZE];
// 解密后后明文数据块
unsigned char outBlock[AES::BLOCKSIZE];
// 必须设定全为0
unsigned char xorBlock[AES::BLOCKSIZE];
DWORD dwOffset = 0;
BYTE *pDecryptData = NULL;
DWORD dwDecryptDataSize = 0;
// 计算密文长度, 并按 128位 即 16字节 对齐, 不够则填充0对齐
// 商
DWORD dwQuotient = dwEncryptData / AES::BLOCKSIZE;
// 余数
DWORD dwRemaind = dwEncryptData % AES::BLOCKSIZE;
if (0 != dwRemaind)
{
dwQuotient++;
}
// 分配解密后的数据缓冲区
dwDecryptDataSize = dwQuotient * AES::BLOCKSIZE;
pDecryptData = new BYTE[dwDecryptDataSize];
if (NULL == pDecryptData)
{
return FALSE;
}
// 设置AES解密密钥
aesDecryptor.SetKey(pAESKey, dwAESKeySize);
do
{
// 初始化数据块
RtlZeroMemory(inBlock, AES::BLOCKSIZE);
RtlZeroMemory(xorBlock, AES::BLOCKSIZE);
RtlZeroMemory(outBlock, AES::BLOCKSIZE);
// 将加密数据块拷贝到输入数据块
if (dwOffset <= (dwDecryptDataSize - AES::BLOCKSIZE))
{
RtlCopyMemory(inBlock, (PVOID)(pEncryptData + dwOffset), AES::BLOCKSIZE);
}
else
{
RtlCopyMemory(inBlock, (PVOID)(pEncryptData + dwOffset), (dwEncryptData - dwOffset));
}
// 使用AES算法进行解密
aesDecryptor.ProcessAndXorBlock(inBlock, xorBlock, outBlock);
// 将解密后的数据块拷贝到输出缓冲区
RtlCopyMemory((PVOID)(pDecryptData + dwOffset), outBlock, AES::BLOCKSIZE);
// 更新数据
dwOffset = dwOffset + AES::BLOCKSIZE;
dwQuotient--;
} while (0 < dwQuotient);
// 返回数据
*ppDecryptData = pDecryptData;
*pdwDecryptData = dwDecryptDataSize;
return TRUE;
}
AESEncrypt 函数用于对输入的原始数据进行AES加密,加密使用指定的AES密钥。函数通过参数返回加密后的数据和数据大小。
函数原型:
BOOL AESEncrypt(
BYTE *pOriginalData, // [in] 原始数据的指针
DWORD dwOriginalDataSize, // [in] 原始数据的大小
BYTE *pAESKey, // [in] AES加密密钥的指针
DWORD dwAESKeySize, // [in] AES加密密钥的大小
BYTE **ppEncryptData, // [out] 指向指针的指针,用于存储加密后的数据
DWORD *pdwEncryptData // [out] 指向DWORD的指针,用于存储加密后的数据大小
);
pOriginalData
: 指向要加密的原始数据的指针。dwOriginalDataSize
: 原始数据的大小。pAESKey
: 指向用于AES加密的密钥的指针。dwAESKeySize
: AES加密密钥的大小。ppEncryptData
: 指向指针的指针,用于存储加密后的数据。该指针需要在函数外释放分配的内存。pdwEncryptData
: 指向DWORD的指针,用于存储加密后的数据大小。
函数返回一个BOOL值,表示操作是否成功。如果函数返回TRUE,则表示加密成功,否则表示加密失败。
AESDecrypt 函数用于对输入的加密后的数据进行AES解密,解密使用指定的AES密钥。函数通过参数返回解密后的数据和数据大小。
函数原型:
BOOL AESDecrypt(
BYTE *pEncryptData, // [in] 加密后的数据的指针
DWORD dwEncryptDataSize, // [in] 加密后的数据的大小
BYTE *pAESKey, // [in] AES解密密钥的指针
DWORD dwAESKeySize, // [in] AES解密密钥的大小
BYTE **ppDecryptData, // [out] 指向指针的指针,用于存储解密后的数据
DWORD *pdwDecryptData // [out] 指向DWORD的指针,用于存储解密后的数据大小
);
pEncryptData
: 指向要解密的加密后数据的指针。dwEncryptDataSize
: 加密后数据的大小。pAESKey
: 指向用于AES解密的密钥的指针。dwAESKeySize
: AES解密密钥的大小。ppDecryptData
: 指向指针的指针,用于存储解密后的数据。该指针需要在函数外释放分配的内存。pdwDecryptData
: 指向DWORD的指针,用于存储解密后的数据大小。
函数返回一个BOOL值,表示操作是否成功。如果函数返回TRUE,则表示解密成功,否则表示解密失败。
调用时通过AESEncrypt
加密数据,AESDecrypt
则用于解密数据;
void ShowData(BYTE *pData, DWORD dwSize)
{
for (int i = 0; i < dwSize; i++)
{
if ((0 != i) &&
(0 == i % 16))
{
printf("\n");
}
else if ((0 != i) &&
(0 == i % 8))
{
printf(" ");
}
printf("%02X ", pData[i]);
}
printf("\n");
}
int main(int argc, char* argv[])
{
BYTE *pEncryptData = NULL;
DWORD dwEncryptDataSize = 0;
BYTE *pDecryptData = NULL;
DWORD dwDecryptDataSize = 0;
char szOriginalData[] = "It’s better to be alone than to be with someone you’re not happy to be with.";
char szAESKey[] = "ABCDEFGHIJKIMNOP";
BOOL bRet = FALSE;
// 加密
bRet = AESEncrypt((BYTE *)szOriginalData, (1 + ::lstrlen(szOriginalData)), (BYTE *)szAESKey, ::lstrlen(szAESKey), &pEncryptData, &dwEncryptDataSize);
if (FALSE == bRet)
{
return 1;
}
// 解密
bRet = AESDecrypt(pEncryptData, dwEncryptDataSize, (BYTE *)szAESKey, ::lstrlen(szAESKey), &pDecryptData, &dwDecryptDataSize);
if (FALSE == bRet)
{
return 2;
}
// 显示
printf("原文数据:\n");
ShowData((BYTE *)szOriginalData, (1 + ::lstrlen(szOriginalData)));
printf("密文数据:\n");
ShowData(pEncryptData, dwEncryptDataSize);
printf("解密后数据:\n");
ShowData(pDecryptData, dwDecryptDataSize);
// 释放内存
delete[]pEncryptData;
pEncryptData = NULL;
delete[]pDecryptData;
pDecryptData = NULL;
system("pause");
return 0;
}
运行后对szOriginalData
中的数据进行加密,密钥是szAESKey
中的长度,如下图所示;
C++ CryptoPP使用AES加解密的更多相关文章
- DES,AeS加解密,MD5,SHA加密
1.DES一共就有4个参数参与运作:明文.密文.密钥.向量.其中这4者的关系可以理解为: 密文=明文+密钥+向量: 明文=密文-密钥-向量: 为什么要向量这个参数呢?因为如果有一篇文章,有几个词重复, ...
- c# Aes加解密和对象序列化
aes加解密 public class AesCryptto { private string key = "hjyf57468jhmuist"; private string i ...
- Java、C#双语版配套AES加解密示例
这年头找个正经能用的东西那是真难,网上一搜索一大堆,正经能用的没几个,得,最后还是得靠自己,正巧遇上需要AES加解密的地方了,而且还是Java和C#间的相互加解密操作,这里做个备忘 这里采用的加解 ...
- AES加解密算法Qt实现
[声明] (1) 本文源码 在一位未署名网友源码基础上,利用Qt编程,实现了AES加解密算法,并添加了文件加解密功能.在此表示感谢!该源码仅供学习交流,请勿用于商业目的. (2) 图片及描述 除图1外 ...
- aes加解密 Illegal key size
做aes加密时,发生一个奇怪的错误,在本地环境是好的,发布到测试环境就出问题, java.security.InvalidKeyException: Illegal key size 想到本地环境之前 ...
- C# RSA加解密与验签,AES加解密,以及与JAVA平台的密文加解密
前言: RSA算法是利用公钥与密钥对数据进行加密验证的一种算法.一般是拿私钥对数据进行签名,公钥发给友商,将数据及签名一同发给友商,友商利用公钥对签名进行验证.也可以使用公钥对数据加密,然后用私钥对数 ...
- Aes加解密,php
Aes类库 <?php namespace Aes; class Aes { /** * var string $method 加解密方法,可通过openssl_get_cipher_metho ...
- cryptoJS AES 加解密简单使用
简单记录一下,前端利用 cryptoJS 如何加解密的.主要是关于 AES 加解密. 需求描述:需要对 url 中的参数进行 AES 解密,然后再把该参数进行 MD5 加密通过接口传递. AES AE ...
- AES加解密程序的实现
AES加解密程序的实现正常情况,用户不能访问sys.dbms_crypto,需要DBA授权:grant execute on dbms_crypto to crm;建立加解密的PKG_AES包:CRE ...
- 收银台数据库存储AES加解密
高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法加密和解密用到的密钥是相同的,这种加密方式加密速度非常快,适合经常发送数据的场合.缺点是密钥的传输 ...
随机推荐
- 鸿蒙HarmonyOS实战-工具安装和Helloworld案例
前言 HarmonyOS是华为自主开发的操作系统,它在2020年9月正式发布.它最初被称为鸿蒙OS,后来更名为HarmonyOS.HarmonyOS旨在提供一种可在各种设备上无缝运行的统一操作系统,包 ...
- 41. 干货系列从零用Rust编写负载均衡及代理,websocket与tcp的映射,WS与TCP互转
wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代 ...
- Flask中本地代理的使用
本地代理 当请求到来时应用上下文和程序上下文被推入本地栈中,全局变量current_app,request,g,session都可以使用了.以current_app为例,current_app代表的是 ...
- IDEA中无法import自己工程中类的问题解决方法
今天开个很久没搞的工程,刚开的时候一片红,很自然的想到,要去配置一下项目的JDK,但是配置好之后,又出了个诡异问题:项目可以运行,但是import项目内部自己写的类的时候,都出现了红色错误.虽然imp ...
- Educational Codeforces Round 97 (Rated for Div. 2) (A - D题个人题解)
1437A. Marketing Scheme 题意:最近猫粮店正在打折销售猫粮罐头,在给定客人能买的罐头数量区间内求合适包装大小 思路:说实话,在比赛刚开始没看懂题,最后放弃读题直接研究给出的样例解 ...
- Web Components从技术解析到生态应用个人心得指北
Web Components浅析 Web Components 是一种使用封装的.可重用的 HTML 标签.样式和行为来创建自定义元素的 Web 技术. Web Components 自己本身不是一个 ...
- 传统与现代可视化 PK:再生水厂二维工艺组态系统
前言 随着可视化技术的进步与发展,传统再生水厂组态系统所展示的组态页面已逐渐无法满足当前现阶段多样化的展示手段.使得系统对污泥处理处置及生产运行成本方面的监控.分析方面较为薄弱,急需对信息化应用成果和 ...
- 基于Kubernetes的Serverless PaaS稳定性建设万字总结
作者:许成铭(竞霄) 数字经济的今天,云计算俨然已经作为基础设施融入到人们的日常生活中,稳定性作为云产品的基本要求,研发人员的技术底线,其不仅仅是文档里承诺的几个九的 SLA 数字,更是与客户切身利益 ...
- <vue 路由 5、动态路由-标签上传递参数>
一.效果 在about页面点击"我的",路径里传入了参数zhangsan,在"我的"页面里接收传递过来的张三并展现出来.注:标签中传递参数写法 二.代码结构 注 ...
- 碎碎念 | 20230326 · 与 SEU & 南传跆协共进晚餐
(碎碎念)今天晚上跟社团一起吃饭,南传的跆协来交流了.南传的人说 他们基本散养,没人正经自习 图书馆基本废弃,校园里有一个大舞台 每天表演,大家每天写剧本 / 演绎 / 拍摄 剪辑,天天喝庆功酒()然 ...