C++ CryptoPP使用AES加解密

微软技术分享
优质创作者: 编程框架技术领域
领域专家: 操作系统技术领域
2023-12-14 08:24:19

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

...全文
647 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
这是一套基于深度学习的智能对话框架,其核心价值在于通过类人交流机制,实现人机间的高效语音互动。系统采用语音作为主要输入输出媒介,涵盖语音辨识、语义理解、对话策略管理及语言生成等多个关键技术环节。该框架通过分析用户语音中的语言模式和上下文,运用大型语言模型实现对用户意图的精准把握与反馈。系统具备实时交互能力,通过优化处理流程与降低响应时延,确保对话过程流畅且无感知停顿。 本项目的显著特性在于支持离线自托管部署模式,用户可在个人硬件设备上独立运行,无需依赖云服务,此举显著提升了数据安全性和隐私保护,并允许在无网络环境下持续工作。系统采用高度模块化的架构,便于功能组件的独立维护、升级或替换,降低了对整体系统进行重构的需求。作为一项开源计划,该项目欢迎全球开发者与研究者参与协作,通过代码贡献与优化建议,共同推动技术迭代与应用创新。 其设计目标聚焦于个人消费级硬件,包括常见的个人电脑、平板和智能手机。为此,系统算法经过深度优化,旨在确保即使在计算资源有限的低功耗设备上,亦能提供流畅无阻的交互响应。提供给开发者的一系列资源包,例如《附赠资源.docx》,内含有丰富的案例分析与API参考文档;《说明文件.txt》则系统性地阐述了快速启动、参数配置及故障排查的详细流程。而核心代码库“sage-main”包含了实现所有功能模块的原生源码,是开发者进行学习和二次开发的基础。 该项目融合了前沿的技术架构、广泛的应用潜力以及简便的部署方式。它不仅为用户创造了一种自然、直观的语音交互体验,同时也为开发者构建了坚实的知识资源和技术支撑。随着人工智能领域持续演进,这套系统有望在未来智能人机交互生态中占据关键位置。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
内容概要:本文聚焦于电液伺服系统在存在非线性与时变特性的工况下,控制策略的性能对比研究,重点分析线性时变模型预测控制(LTV-MPC)与传统PID控制的差异。通过Matlab平台实现了系统建模、控制器设计及仿真验证,系统阐述了LTV-MPC在处理动态变化和非线性扰动方面相较于PID所具有的优越性,尤其体现在更高的控制精度、更强的鲁棒性以及更优的动态响应能力。文档提供了完整的代码实现与技术说明,涵盖系统动力学建模、状态空间表示、预测模型构建、滚动优化求解以及闭环仿真全过程,有助于读者深入理解先进控制算法的设计原理与工程实现路径。; 适合人群:具备自动控制理论基础、状态空间分析能力和Matlab/Simulink仿真经验的研究生、科研人员及从事机电系统、液压传动与控制、先进控制算法开发的工程技术人员,特别适用于开展高性能伺服系统研究或撰写相关课题论文的专业人士。; 使用场景及目标:① 掌握电液伺服系统的非线性建模与动态特性分析方法;② 学习并实现LTV-MPC控制算法,提升对复杂时变系统的控制性能;③ 深入对比PID与MPC在瞬态响应、稳态误差、抗干扰能力等方面的差异,为实际工程中控制器选型提供量化依据;④ 支持学术论文复现、课程设计、毕业设计及科研项目中的控制方案优化需求。; 阅读建议:建议结合Matlab代码逐模块分析,重点关注系统建模、预测模型推导、代价函数设计、约束处理及仿真结果对比部分,动手调整控制器参数以观察不同工况下的性能变化,从而深化对MPC滚动优化机制和反馈校正思想的理解。同时可参考文中提及的其他先进控制方法拓展研究视野。

6,725

社区成员

发帖
与我相关
我的任务
社区描述
微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。
windowsmicrosoft 企业社区
社区管理员
  • 微软技术分享
  • 郑子铭
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。

予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。

试试用AI创作助手写篇文章吧