OpenSSL之AES加密算法 您所在的位置:网站首页 aes算法实现文件加密软件 OpenSSL之AES加密算法

OpenSSL之AES加密算法

2024-07-12 10:22| 来源: 网络整理| 查看: 265

本文属于《OpenSSL加密算法库使用系列教程》之一,欢迎查看其它文章。

实战篇-OpenSSL之AES加密算法-ECB模式 一、AES简介二、ECB模式 1、命令行操作2、函数说明3、编程实现 (1)PKCS7填充方式(2)实现ECB模式加解密(3)测试代码

一、AES简介

密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。

这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

AES属于对称加密算法,加解密使用同一个秘钥。

对称加密算法,一般有至少4种模式,即ECB、CBC、CFB、OFB等。

具体的加密原理,就不进行介绍了,本文主要从使用角度,进行说明。

以下命令行和编程实现,均基于OpenSSL开源库。在命令行中,我们可以使用命令实现对文件加解密,以验证我们的编程实现,是否正确。

二、ECB模式

电子密码本模式 Electronic Code Book(ECB)。这种模式是最早采用和最简单的模式,它将加密的数据分成若干组,每组的大小跟加密 密钥长度相同,然后每组都用相同的密钥进行加密。

其缺点是:电子编码薄模式用一个密钥加密消息的所有块,如果原消息中重复明文 块,则加密消息中的相应密文块也会重复,因此,电子编码薄模式适于加密小消息。

1、命令行操作

使用aes-128-ecb对hello.txt加密,128位密钥为8cc72b05705d5c46f412af8cbed55aad,密文为hello.en。

openssl enc -e -aes-128-ecb -in hello.txt -out hello.en -K 8cc72b05705d5c46f412af8cbed55aad

使用aes-128-ecb对hello.en解密,128位密钥为8cc72b05705d5c46f412af8cbed55aad,解密后的文件为hello.de。

openssl enc -d -aes-128-ecb -in hello.en -out hello.de -K 8cc72b05705d5c46f412af8cbed55aad 2、函数说明

生成加密/解密的Key:

int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key); 参数名称含义userKey用户指定的密码。注意:只能是16/24/32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度。bits密码位数。即userKey的长度 * 8,只能是128/192/256位。key向外输出参数返回值0 - 成功; -1 - userkey,key为空;-2 - 密钥长度不是128/192/256

AES ECB加密/解密:

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc); 参数名称含义in输入数据,长度固定为16字节out输出数据,长度与输入数据一致,固定为16字节key使用AES_set_encrypt_key/AES_set_decrypt_key生成的KeyencAES_ENCRYPT 代表加密, AES_DECRYPT代表解密 3、编程实现

由于ECB模式,每次只能处理一个块的数据,即16字节,所以如果需要处理任意长度的数据,那么需要在原始数据末尾,先进行填充,使得数据长度为16的整数倍,随后再分块进行加密。解密时,也需要分块解密,最后将解密后的数据,进行取消填充。

(1)PKCS7填充方式

AES支持多种填充方式:如NoPadding、PKCS5Padding、ISO10126Padding、PKCS7Padding、ZeroPadding。密文长度与填充方式关系,可参考《AES加密模式和填充模式》。

PKCS7填充方式:

假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。

举个例子最直观,这里以块大小为16字节,进行PKCS7填充,如下:

数据1: {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A} 填充后:{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06} 尾部填充了6个6,填充后数据长度为16。 数据2: {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10} 填充后:{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10} 尾部填充了16个16,填充后数据长度为32。

Padding类实现了上述的PKCS7填充功能,如下:

Padding.h

#ifndef PADDING_H #define PADDING_H #include /** * @brief The Padding class * 算法数据填充模式,提供对数据进行PKCS7填充和去除填充的相关函数。 */ class Padding { public: static int getPKCS7PaddedLength(int dataLen, int alignSize); static QByteArray PKCS7Padding(const QByteArray &in, int alignSize); static QByteArray PKCS7UnPadding(const QByteArray &in); }; #endif // PADDING_H

Padding.cpp

#include "Padding.h" /** * @brief Padding::getPKCS7PaddedLength * 根据原始数据长度,计算进行PKCS7填充后的数据长度 * @param dataLen 原始数据长度 * @param alignSize 对齐字节数 * @return 返回填充后的数据长度 */ int Padding::getPKCS7PaddedLength(int dataLen, int alignSize) { // 计算填充的字节数(按alignSize字节对齐进行填充) int remainder = dataLen % alignSize; int paddingSize = (remainder == 0) ? alignSize : (alignSize - remainder); return (dataLen + paddingSize); } /** * @brief Padding::PKCS7Padding * 采用PKCS7Padding方式,将in数据进行alignSize字节对齐填充。 * 此函数用于加密前,对明文进行填充。 * @param in 数据 * @param alignSize 对齐字节数 * @return 返回填充后的数据 */ QByteArray Padding::PKCS7Padding(const QByteArray &in, int alignSize) { // 计算需要填充字节数(按alignSize字节对齐进行填充) int remainder = in.size() % alignSize; int paddingSize = (remainder == 0) ? alignSize : (alignSize - remainder); // 进行填充 QByteArray temp(in); temp.append(paddingSize, paddingSize); return temp; } /** * @brief Padding::PKCS7UnPadding * 采用PKCS7Padding方式,将in数据去除填充。 * 此函数用于解密后,对解密结果进一步去除填充,以得到原始数据。 * @param in 数据 * @return 返回去除填充后的数据 */ QByteArray Padding::PKCS7UnPadding(const QByteArray &in) { char paddingSize = in.at(in.size() - 1); return in.left(in.size() - paddingSize); }

代码比较简单,注释也说的很明白啦。

(2)实现ECB模式加解密

下面,函数已经封装完毕,如下:

#include "AES.h" #include #include #include "Padding.h" /** * @brief AES::ecb_encrypt * ECB模式加解密,填充模式采用PKCS7Padding, * 支持对任意长度明文进行加解密。 * @param in 输入数据 * @param out 输出结果 * @param key 密钥,长度必须是16/24/32字节,否则加密失败 * @param enc true-加密,false-解密 * @return 执行结果 */ bool AES::ecb_encrypt(const QByteArray &in, QByteArray &out, const QByteArray &key, bool enc) { // 检查密钥合法性(只能是16、24、32字节) Q_ASSERT(key.size() == 16 || key.size() == 24 || key.size() == 32); if (enc) { // 生成加密key AES_KEY aes_key; if (AES_set_encrypt_key((const unsigned char*)key.data(), key.size() * 8, &aes_key) != 0) { return false; } // 进行PKCS7Padding填充 QByteArray inTemp = Padding::PKCS7Padding(in, AES_BLOCK_SIZE); // 执行ECB模式加密 out.resize(inTemp.size()); // 调整输出buf大小 for (int i = 0; i // 生成解密key AES_KEY aes_key; if (AES_set_decrypt_key((const unsigned char*)key.data(), key.size() * 8, &aes_key) != 0) { return false; } // 执行ECB模式解密 out.resize(in.size()); // 调整输出buf大小 for (int i = 0; i data.resize(size); for (int i = 0; i QByteArray plainText = data; QByteArray encryptText; QByteArray decryptText; QByteArray key = QByteArray::fromHex("8cc72b05705d5c46f412af8cbed55aad"); // AES ecb模式加密验证 AES aes; aes.ecb_encrypt(plainText, encryptText, key, true); // 加密 aes.ecb_encrypt(encryptText, decryptText, key, false); // 解密 qDebug()


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有