C++ CryptoPP使用AES加解密

news2024/9/24 17:11:50

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是木马

木马 1. 定义2. 木马的特征3. 木马攻击流程4. 常见木马类型5. 如何防御木马 1. 定义 木马一名来源于古希腊特洛伊战争中著名的“木马计”&#xff0c;指可以非法控制计算机&#xff0c;或在他人计算机中从事秘密活动的恶意软件。 木马通过伪装成正常软件被下载到用户主机&…

strstr 的使用和模拟实现

就位了吗&#xff1f;如果坐好了的话&#xff0c;那么我就要开始这一期的表演了哦&#xff01; strstr 的使用和模拟实现: char * strstr ( const char * str1, const char * str2); Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 i…

030 - STM32学习笔记 - ADC(四) 独立模式多通道DMA采集

030 - STM32学习笔记 - ADC&#xff08;四&#xff09; 独立模式多通道DMA采集 中断模式和DMA模式进行单通道模拟量采集&#xff0c;这节继续学习独立模式多通道DMA采集&#xff0c;使用到的引脚有之前使用的PC3&#xff08;电位器&#xff09;&#xff0c;PA4&#xff08;光敏…

Peter算法小课堂—高精度乘法

给大家看个小视频13 高精度算法 乘法_哔哩哔哩_bilibili 乘法竖式 大家觉得Plan A好&#xff0c;还是Plan B好呢&#xff08;对于计算机来说&#xff09;&#xff1f;那显然是B啦 x*y问题 mul思路&#xff1a;mul()函数返回x数组乘y数组的积&#xff0c;保存在z数组。根据上…

基于SpringBoot的旅游网站的设计与实现

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff0c;旅游网站当然也不能排除在外&#xff0c;随着旅游网站的不断成熟&#xff0c;它彻底改变了过去传统的旅游网站方式&#xff0c;不仅使旅游管理…

three.js结合vue

作者&#xff1a;baekpcyyy&#x1f41f; 1.搭建环境 ps&#xff1a;这里要按照node.js在之前有关vue搭建中有介绍 新建文件夹并在vsc终端中打开 1.输入vite创建指令 npm init vitelatest然后我们cd进入刚才创建的目录下 npm install安装所需依赖 npm run dev启动该项目 …

Python正则表达式:match()和search()函数全面解读

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;正则表达式是强大的工具&#xff0c;能够用于文本匹配、搜索和替换。re模块提供了许多函数来处理正则表达式&#xff0c;其中match()和search()是两个常用的函数。本文将深入探讨这两个函…

论文复现代码《基于自适应哈夫曼编码的密文可逆信息隐藏算法》调试版

前言 本文展示论文《基于自适应哈夫曼编码的密文可逆信息隐藏算法》的复现代码。代码块的结构如下&#xff1a; 其中&#xff0c;每个代码块都包含了测试该代码块的功能的主函数代码&#xff0c;使用时可放心运行&#xff0c;前提是你按照这个包结构把文件命名改好&#xff0c…

vue3 keep-alive页面切换报错:parentComponent.ctx.deactivate is not a function

问题&#xff1a; <router-view v-slot"{ Component }"><keep-alive ><component :is"Component" v-if"$route.meta.keepAlive" /></keep-alive><component :is"Component" v-if"!$route.meta.keepA…

【软件测试】白盒测试和黑盒测试

一、软件测试基本分类 一般地&#xff0c;我们将软件测试活动分为以下几类&#xff1a;黑盒测试、白盒测试、静态测试、动态测试、手动测试、自动测试等等。 黑盒测试 黑盒测试又叫功能测试、数据驱动测试或给予需求规格说明书的功能测试。这种测试注重于测试软件的功能性需…

java二十章多线程

概念 有很多工作是可以同时完成的&#xff0c;这种思想放在Java中被称为并发&#xff0c;并发完成每一件事被称为线程。 程序员可以在程序中执行多个线程&#xff0c;每一个线程完成一个功能//与其他线程并发执行&#xff0c;这种机制被称为多线程&#xff0c;并不算所有编程…

PLC:200smart(13-16章)

PLC&#xff1a;200smart 第十三章2、带参子程序3、将子程序设置成库文件 第十三章 项目ValueValue主程序MAIN一个项目只能有一个&#xff0c;循环扫描子程序SBR_0项目中最多有128个&#xff0c;只有在调用时 才执行&#xff08;子程序可以嵌套其他子程序&#xff0c;最多八层…

广州华锐视点:基于VR元宇宙技术开展法律法规常识在线教学,打破地域和时间限制

随着科技的飞速发展&#xff0c;人类社会正逐渐迈向一个全新的时代——元宇宙。元宇宙是一个虚拟的、数字化的世界&#xff0c;它将现实世界与数字世界紧密相连&#xff0c;为人们提供了一个全新的交流、学习和娱乐平台。在这个充满无限可能的元宇宙中&#xff0c;法律知识同样…

构建个人代理池:使用GitHub项目proxy_pool的搭建配置及代码接口详解

手把手教你搭建代理IP池&#xff1a; 项目简介&#xff1a; ​ 爬虫代理IP池项目,主要功能为定时采集网上发布的免费代理验证入库&#xff0c;定时验证入库的代理保证代理的可用性&#xff0c;提供API和CLI两种使用方式。同时你也可以扩展代理源以增加代理池IP的质量和数量。…

分治法之归并排序

思路: 将待排序数组分成两个子数组&#xff0c;计算中间位置mid。对左半部分进行递归排序&#xff0c;得到一个有序的子数组。对右半部分进行递归排序&#xff0c;得到另一个有序的子数组。合并两个有序的子数组&#xff0c;得到一个完整的有序数组。 示例图: 代码: #include&…

WPF绘制进度条(弧形,圆形,异形)

前言 WPF里面圆形进度条实现还比较麻烦,主要涉及到的就是动态绘制进度条的进度需要用到简单的数学算法。其实原理比较简单,我们需要的是话两条重叠的弧线,里面的弧线要比里面的弧线要宽,这样简单的雏形就出来了。 基础写法 我们可以用Path来绘制弧线,代码如下: <Gr…

Linux:服务器管理工具宝塔(bt)安装教程

一、简介 bt宝塔Linux面板是提升运维效率的服务器管理软件&#xff0c;支持一键LAMP/LNMP/集群/监控/网站/FTP/数据库/JAVA等多项服务的管理功能 二、安装 使用 SSH 连接工具&#xff0c;如堡塔SSH终端连接到您的 Linux 服务器后&#xff0c;挂载磁盘&#xff0c;根据系统执…

C++基础——文件操作

文章目录 1 概述2 文本文件2.1 写文件2.1.1 写文件流程2.1.2 文件打开方式 2.2 读文件 3 二进制文件3.1 写文件3.2 读文件 1 概述 程序最基本的操作之一就是文件操作&#xff0c;程序运行时的数据都是临时数据&#xff0c;当程序结束后就不复存在了。通常都是通过文件或其他持…

酷狗音乐app 评论signature

文章目录 声明目标加密参数定位翻页逻辑代码实现 声明 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请私信我立即删除&#xff01; 目标 复制curl转python # -*- c…

SQL 数据操作技巧:SELECT INTO、INSERT INTO SELECT 和 CASE 语句详解

SQL SELECT INTO 语句 SELECT INTO 语句将数据从一个表复制到一个新表中。 SELECT INTO 语法 将所有列复制到新表中&#xff1a; SELECT * INTO newtable [IN externaldb] FROM oldtable WHERE condition;只复制一些列到新表中&#xff1a; SELECT column1, column2, colu…