本文属于《OpenSSL加密算法库使用系列教程》之一,欢迎查看其它文章。
密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS
PUB 197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。
AES属于对称加密算法,加解密使用同一个秘钥。
对称加密算法,一般有至少4种模式,即ECB、CBC、CFB、OFB等。
具体的加密原理,就不进行介绍了,本文主要从使用角度,进行说明。
以下命令行和编程实现,均基于OpenSSL开源库。在命令行中,我们可以使用命令实现对文件加解密,以验证我们的编程实现,是否正确。
输出反馈模式 Output Feedback Mode(OFB)。输出反馈模式与CFB 相似,惟一差别是,CFB 中密文填入加密过程下一阶段,而 在OFB 中,初始化向量加密过程的输入填入加密过程下一阶段。
使用aes-128-ofb对hello.txt加密,128位密钥为8cc72b05705d5c46f412af8cbed55aad,初始化向量为667b02a85c61c786def4521b060265e8,密文为hello.en。
openssl enc -e -aes-128-ofb -in hello.txt -out hello.en -K 8cc72b05705d5c46f412af8cbed55aad -iv 667b02a85c61c786def4521b060265e8
使用aes-128-ofb对hello.en解密,128位密钥为8cc72b05705d5c46f412af8cbed55aad,初始化向量为667b02a85c61c786def4521b060265e8,解密后的文件为hello.de。
openssl enc -d -aes-128-ofb -in hello.en -out hello.de -K 8cc72b05705d5c46f412af8cbed55aad -iv 667b02a85c61c786def4521b060265e8
AES OFB128加密/解密:
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, int *num);
参数名称 | 含义 |
---|---|
in | 输入数据,长度任意 |
out | 输出数据,长度与输入数据相等 |
length | 输入数据的长度,字节数 |
key | 使用AES_set_encrypt_key生成的Key |
ivec | 可读写的一块内存。长度必须是16字节。 |
num | 应总是为0,否则会触发断言 |
AES_ofb128_encrypt在加密的过程中会修改ivec的内容,因此ivec参数不能是一个常量,而且不能在传递给加密函数后再立马传递给解密函数,必须重新赋值之后再传递给解密函数。
可以看到该函数没有加密和解密标识参数enc,即表明当in为明文时,执行的是加密操作;当in为密文时,执行的是解密操作,相当于是对等的。
下面,函数已经封装完毕,如下:
/**
* @brief AES::ofb128_encrypt
* OFB128模式加解密,支持对任意长度明文进行加解密。
* @param in 输入数据
* @param out 输出结果
* @param key 密钥,长度必须是16/24/32字节,否则加密失败
* @param ivec 初始向量,长度必须是16字节
* @param enc true-加密,false-解密
* @return 执行结果
*/
bool AES::ofb128_encrypt(const QByteArray &in, QByteArray &out, const QByteArray &key, const QByteArray &ivec, bool enc)
{
// 检查密钥合法性(只能是16、24、32字节)
Q_ASSERT(key.size() == 16 || key.size() == 24 || key.size() == 32);
Q_ASSERT(ivec.size() == 16); // 初始向量为16字节
// 特别注意:OFB模式加密和解密均使用加密key。
// 生成加密key
AES_KEY aes_key;
if (AES_set_encrypt_key((const unsigned char*)key.data(), key.size() * 8, &aes_key) != 0)
{
return false;
}
Q_UNUSED(enc);
// 特别注意:加密与解密执行相同的操作
// 执行OFB128模式加密或解密
int num = 0;
QByteArray ivecTemp = ivec; // ivec会被修改,故需要临时变量来暂存
out.resize(in.size()); // 调整输出buf大小
AES_ofb128_encrypt((const unsigned char*)in.data(),
(unsigned char*)out.data(),
in.size(),
&aes_key,
(unsigned char*)ivecTemp.data(),
&num);
return true;
}
加解密过程:
经测试,本函数支持对任意长度输入数据进行加解密。
void createTestData(QByteArray& data, int size)
{
data.resize(size);
for (int i = 0; i < size; i++)
{
data[i] = i % 128;
}
}
void testAES(const QByteArray& data)
{
QByteArray plainText = data;
QByteArray encryptText;
QByteArray decryptText;
QByteArray key = QByteArray::fromHex("8cc72b05705d5c46f412af8cbed55aad");
QByteArray ivec = QByteArray::fromHex("667b02a85c61c786def4521b060265e8");
// AES ofb128模式加密验证
AES aes;
aes.ofb128_encrypt(plainText, encryptText, key, ivec, true); // 加密
aes.ofb128_encrypt(encryptText, decryptText, key, ivec, false); // 解密
qDebug() << "AES ofb128 encrypt verify" << ((decryptText == plainText) ? "succeeded" : "failed");
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 产生1MB+3B的测试数据,为了使该测试数据长度,不为8或16的整数倍
QByteArray data;
createTestData(data, 1*1024*1024+3);
// 测试AES
testAES(data); // 测试,直接调用OpenSSL中AES算法函数
return a.exec();
}
执行结果:
本文涉及工程代码地址:https://gitee.com/bailiyang/cdemo/tree/master/Qt/49OpenSSL/OpenSSL
若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!
同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。