C++ CryptoPP使用AES加解密

Crypto++ (CryptoPP) 是一个用于密码学和加密的 C++ 库。它是一个开源项目,提供了大量的密码学算法和功能,包括对称加密、非对称加密、哈希函数、消息认证码 (MAC)、数字签名等。Crypto++ 的目标是提供高性能和可靠的密码学工具,以满足软件开发中对安全性的需求。

高级加密标准(Advanced Encryption Standard,AES)是一种对称密钥加密标准,用于保护电脑上的敏感数据。AES是由美国国家标准与技术研究院(NIST)于2001年确定的,它取代了过时的数据加密标准(Data Encryption Standard,DES)。

以下是AES加密算法的主要特点和概述:

  1. 对称密钥算法: AES是一种对称密钥算法,意味着相同的密钥用于加密和解密数据。这就要求通信双方在通信前共享密钥,并确保其保密性。
  2. 分组密码: AES将明文数据分成固定大小的块(128比特),然后对每个块进行独立的加密。这个固定大小的块称为分组。AES支持多种分组长度,包括128比特、192比特和256比特。
  3. 轮数: AES加密算法的安全性与其轮数相关。轮数表示对数据块的处理循环次数,不同密钥长度的AES使用不同数量的轮数。通常,128比特密钥使用10轮,192比特密钥使用12轮,256比特密钥使用14轮。
  4. 密钥长度: AES支持多种密钥长度,包括128比特、192比特和256比特。密钥长度的选择直接影响加密算法的安全性。
  5. SubBytes、ShiftRows、MixColumns和AddRoundKey: 这些是AES加密算法中的四个主要操作,它们通过多轮迭代来加密数据。SubBytes和ShiftRows引入非线性性,MixColumns和AddRoundKey提供了扩散和混淆。
  6. 强安全性: 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算法进行加密的函数。下面是对函数的主要步骤的注释:

  1. AES加密对象初始化:
    • 创建AESEncryption对象用于AES加密。
    • 定义AES加密需要的数据块:inBlock(输入数据块)、outBlock(输出数据块)、xorBlock(异或数据块)。
  2. 计算加密数据块大小:
    • 计算需要的加密数据块数量,考虑到原始数据大小可能不是AES块大小的整数倍。
  3. 分配加密后的数据缓冲区:
    • 根据计算得到的加密数据块大小分配内存。
  4. 设置AES加密密钥:
    • 调用SetKey函数设置AES加密密钥。
  5. AES加密过程:
    • 循环处理原始数据块,每次处理一个AES块大小的数据。
    • 将原始数据块拷贝到输入数据块。
    • 使用AES算法进行加密。
    • 将加密后的数据块拷贝到输出缓冲区。
  6. 返回加密结果:
    • 返回加密后的数据缓冲区和大小。

请注意,在实际使用中,要确保释放了分配的内存,以防止内存泄漏。

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算法进行解密的函数。以下是对函数的主要步骤的注释:

  1. AES解密对象初始化:
    • 创建AESDecryption对象用于AES解密。
    • 定义AES解密需要的数据块:inBlock(输入数据块)、outBlock(输出数据块)、xorBlock(异或数据块)。
  2. 计算解密数据块大小:
    • 计算需要的解密数据块数量,考虑到加密数据大小可能不是AES块大小的整数倍。
  3. 分配解密后的数据缓冲区:
    • 根据计算得到的解密数据块大小分配内存。
  4. 设置AES解密密钥:
    • 调用SetKey函数设置AES解密密钥。
  5. AES解密过程:
    • 循环处理加密数据块,每次处理一个AES块大小的数据。
    • 将加密数据块拷贝到输入数据块。
    • 使用AES算法进行解密。
    • 将解密后的数据块拷贝到输出缓冲区。
  6. 返回解密结果:
    • 返回解密后的数据缓冲区和大小。

请注意,在实际使用中,要确保释放了分配的内存,以防止内存泄漏。

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中的长度,如下图所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/203754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

05-React路由(Router 5版本)

React路由背景介绍 背景介绍 多页面应用与SPA单页面应用 多页面应用 先说传统的多页面&#xff0c;需要写多个子页面 点击导航栏&#xff0c;整个页面都会刷新&#xff0c;但是实际上我只想刷新一小块的内容&#xff0c;其他东西变化不大 而且这个单页面&#xff0c;每次切…

风光互补路灯简介及配置方案

风光互补路灯是一种新型的路灯系统&#xff0c;使用太阳能和风能进行发电&#xff0c;以供给路灯照明。它结合了太阳能光伏板和垂直轴风力发电机&#xff0c;可以在一天内不同的时间段和天气条件下&#xff0c;通过自然资源发电&#xff0c;实现能源的自给自足和环境保护。 风…

鸿蒙系统扫盲(三):鸿蒙开发用什么语言?

1.两种开发方向 我们常说鸿蒙开发&#xff0c;但是其实鸿蒙开发分为两个方向&#xff1a; 一个是系统级别的开发&#xff0c;比如驱动&#xff0c;内核和框架层的开发&#xff0c;这种开发以C/C为主 还有一个是应用级别的开发&#xff0c;在API7以及以下&#xff0c;还是支持…

attention中Q,K,V的理解

第一种 1.首先定义三个线性变换矩阵&#xff0c;query&#xff0c;key&#xff0c;value&#xff1a; class BertSelfAttention(nn.Module):self.query nn.Linear(config.hidden_size, self.all_head_size) # 输入768&#xff0c; 输出768self.key nn.Linear(config.hidde…

Open3D 最小二乘拟合二维直线(直接求解法)

目录 一、算法原理二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。爬虫网站自重。 一、算法原理 平面直线的表达式为: y = k x + b

台灯选什么样的对眼睛好?分享适合备考使用的护眼台灯

随着生活条件的逐渐提升&#xff0c;台灯的需求也越来越大&#xff0c;不管在生活中还是工作中&#xff0c;台灯成为了必不可少的照明工具。而且现在很多孩子都是存在视力问题的&#xff0c;这也让不少家长纷纷开始重视起来&#xff0c;为了更好的保护孩子的眼睛选择更为专业的…

数据探索:五款免费数据可视化工具概览

数据可视化是解读和传达数据的重要方式&#xff0c;而现在有许多免费的工具可供选择&#xff0c;让您在探索数据时更轻松、更有趣。以下是五款推荐的免费数据可视化工具&#xff1a; Tableau Public&#xff1a; Tableau Public是一款功能强大的可视化工具&#xff0c;能够创建…

SpringBoot项目打成jar包后,上传的静态资源(图片等)如何存储和访问

1.问题描述&#xff1a; 使用springboot开发一个项目&#xff0c;开发文件上传的时候&#xff0c;通常会将上传的文件存储到资源目录下的static里面&#xff0c;然后在本地测试上传文件功能没有问题&#xff0c;但是将项目打成jar包放到服务器上运行的时候就会报错&#xff0c…

指标管理必知的真相:订单事实表里没有原子指标

上篇文章「一个问题鉴定指标管理真实力&#xff1a;订单表里有原子指标吗&#xff1f;」写完以后&#xff0c;分享到一个群里&#xff0c;有同行回复&#xff1a;有&#xff0c;比如订单金额。 看到回复&#xff0c;我脑子突然就断电了&#xff0c;好像对诶&#xff01;确实是…

借助 DPM 代码扫描的力量解锁医疗设备的可追溯性

在当今的医疗保健系统中&#xff0c;医疗设备的可追溯性变得比以往任何时候都更加重要。为了增强现代医疗保健领域的可追溯性和安全性&#xff0c;UDI 条形码充当唯一设备标识的标准&#xff0c;为医疗设备提供唯一标识符。 DataMatrix 代码&#xff08;或直接零件标记代码&am…

Python爬取某电商平台商品数据及评论!

目录 前言 主要内容 1. 爬取商品列表数据 2. 爬取单个商品页面的数据 3. 爬取评论数据 4. 使用代理ip 总结 前言 随着互联网的发展&#xff0c;电商平台的出现让我们的消费更加便利&#xff0c;消费者可以在家里轻松地购买到各种商品。但有时候我们需要大量的商品数据进…

网络和Linux网络_7(传输层)UDP和TCP协议(端口号+确认应答+超时重传+三次握手四次挥手)

目录 1. 重看端口号 1.1 端口号的概念 1.2 端口号的划分 2. 重看UDP协议 2.1 UDP协议格式 2.2 UDP的特点 3. 重看TCP协议 3.1 TCP协议格式 3.2 TCP的解包分用 3.3 TCP的可靠性及机制 3.3.1 确认应答ACK机制 3.3.2 超时重传机制 3.3.3 连接管理机制&#xff08;三次…

内存泄漏检测工具valgrind

示例&#xff1a; class Person { public:Person(int age){//将年龄数据开辟到堆区m_Age new int(age);}//重载赋值运算符 写法2 此代码在linux测试Person& operator(Person& p){*m_Age *p.m_Age; //通过linux下valgrind工具检测&#xff0c;无内存泄漏情况。//此语…

LVS+Keepalived实验

实验前准备 主DR服务器&#xff1a;(ens33)192.168.188.11 ipvsadm、keepalived (ens33:0)192.168.188.188 备DR服务器&#xff1a;(ens33)192.168.188.12 ipvsadm、keepalived (ens33:0)192.168.188.188 Wbe服务器1&#xff1a;(ens33)192.168.188.13 (lo:0)192.168.188.188 W…

UG\NX二次开发 获取对象上属性的锁定状态UF_ATTR_ask_locked

文章作者&#xff1a;里海 来源网站&#xff1a;里海NX二次开发3000例专栏 感谢粉丝订阅 感谢 2301_80435318 开发 订阅本专栏&#xff0c;非常感谢。 简介 设置对象上属性的锁定状态UF_ATTR_set_locked&#xff0c;需要先在“用户默认设置”中勾选“通过NX Open锁定属性”&…

【攻防世界-misc】[简单] 凯撒大帝在培根里藏了什么

1.下载文件&#xff0c;打开后是这样子的 2.根据题目提示说是有凯撒密码和培根密码&#xff0c;因为文件内容为AB形式&#xff0c;不符合凯撒条件&#xff0c;所以先用培根解&#xff0c;将文件内容复制&#xff0c;CTF在线工具-CTF工具|CTF编码|CTF密码学|CTF加解密|程序员工具…

虚拟机安装centos7系统后网络配置

一.桥接网络和nat网络的区别1&#xff0c;桥接模式&#xff08;如果外部访问虚拟机&#xff0c;最好选这个&#xff09; 通过使用物理机网卡 具有单独ip,但是需要手动配置。 在bridged模式下&#xff0c;VMWare虚拟出来的操作系统就像是局域网中的一台独立的主机&#xff0c;它…

数字孪生智慧园区:企业与政府合作的共赢之选

随着科技的快速发展和数字化转型的推动&#xff0c;数字孪生技术正逐渐成为智慧城市和园区建设的重要方向。数字孪生智慧园区&#xff0c;以数字孪生技术为驱动&#xff0c;通过对园区实体和虚拟环境的全面感知和深度理解&#xff0c;为园区管理者和入驻企业提供智能化决策支持…

2023 BUCT 计算方法实验报告

前言 Textlive版本&#xff1a;2023 textstudio版本&#xff1a;4.6.3 名字和日期在以下地方修改: 图片下载地址; figures.zip LiangCha_Xyy/Source - Gitee.com 如下图&#xff0c;.tex文件和figures文件夹放在同一路径下即可 .tex代码 \documentclass[UTF8]{ctexart} \usep…

行业研究:2023年建筑涂料市场需求及发展方向分析

目前绿色化经济成为社会经济主旋律&#xff0c;涂料行业作为高污染行业&#xff0c;国家层面出台了一系列政策规划引导行业向绿色、安全、环保发展。例如&#xff0c;禁止使用高VOCs含量的溶剂型涂料&#xff0c;推广水性涂料等低VOCs含量涂料&#xff0c;鼓励外商投资高性能涂…