在我们上一篇文章中,我们介绍了如何安装Crypto++,以及用它完成我们第一个程序。这篇文章主要用来介绍上一篇中的AES程序。
首先让我们来了解一下AES是什么。这部分是准备给对AES不熟的读者看的,了解的读者可直接跳到后文的程序部分。
AES是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。1998年NIST开始AES第一轮分析、测试和征集,共产生了15个候选算法。1999年3月完成了第二轮AES的分析、测试。2000年10月2日美国政府正式宣布选中比利时密码学家Joan Daemen 和 Vincent Rijmen 提出的一种密码算法RIJNDAEL 作为 AES。高级加密标准由NIST于2001年11月26日发布于FIPS PUB 197,并在2002年5月26日成为有效的标准。
AES加密数据块分组长度必须为128比特,密钥长度可以是128比特、192比特、256比特中的任意一个(如果数据块及密钥长度不足时,会补齐),分别称为AES-128、AES-192和AES-256。AES加密有很多轮的重复和变换。大致步骤如下:1、密钥扩展(KeyExpansion),2、初始轮(Initial Round),3、重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,4、最终轮(Final Round),最终轮没有MixColumns。
Crypto++库很好的一点是,不用我们手动的对明文块或者密文块进行分组,而是在实现中自动完成了,这样就减少了我们的工作量。
等等,那AES在分组的时候,有没有什么标准?难道只是将需要加密的信息分成128bit的一块块吗?事实上不是这个样子的。AES作为分组密码的一种,而分组密码从DES时代起就拥有了很多种的工作模式。下面简要介绍各种模式。(部分文字及图片来自维基百科)
(1) ECB模式
最简单的加密模式即为电子密码本(Electronic codebook,ECB)模式。需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。简单的理解,ECB模式就是将很长的明文,按照128bit分组,不足补零。每组用相同密钥进行加密,最后将各组密文拼在一起即可。就是分割处理的想法,各个不同的明文块和密文块之间没有运算关系。
ECB模式的优点是可并行运算,速度快,易于标准化。缺点是分组加密不能隐蔽数据模式,即相同的明文组蕴含着相同的密文组;不能抵抗组的重放、嵌入、删除等攻击;加密长度只能是分组的倍数。
(2) CBC模式
1976年,IBM发明了密码分组链接(CBC,Cipher-block chaining)模式。在CBC模式中,每个明文块先与前一个密文块进行异或后,再进行加密。在这种方法中,每个密文块都依赖于它前面的所有明文块。同时,为了保证每条消息的唯一性,在第一个块中需要使用初始化向量。
(3) CFB
密文反馈(CFB,Cipherfeedback)模式类似于CBC,可以将块密码变为自同步的流密码;工作过程亦非常相似,CFB的解密过程几乎就是颠倒的CBC的加密过程。
(4)OFB
输出反馈模式(Outputfeedback, OFB)可以将块密码变成同步的流密码。它产生密钥流的块,然后将其与明文块进行异或,得到密文。与其它流密码一样,密文中一个位的翻转会使明文中同样位置的位也产生翻转。这种特性使得许多错误校正码,例如奇偶校验位,即使在加密前计算而在加密后进行校验也可以得出正确结果。由于XOR操作的对称性,加密和解密操作是完全相同的。
(5)CTR
与OFB相似,CTR将块密码变为流密码。它通过递增一个加密计数器以产生连续的密钥流,其中,计数器可以是任意保证不产生长时间重复输出的函数,但使用一个普通的计数器是最简单和最常见的做法。CTR模式的特征类似于OFB,但它允许在解密时进行随机存取。由于加密和解密过程均可以进行并行处理,CTR适合运用于多处理器的硬件上。
注意图中的“nonce(随机数)”与其它图中的IV(初始化向量)相同。IV、随机数和计数器均可以通过连接,相加或异或使得相同平文产生不同的密文。
(6)CBC_CTS
即应用了密文窃取(Ciphertextstealing)技术的CBC。
我们在上面的介绍中可以注意到,ECB和CBC两种模式,其输出密文长度永远都是分块大小(128bits)的整数倍,而其他模式都是和输入明文等长。为了解决输出密文偏长的情况,就可以采用密文窃取方式。CBC_CTS具体过程如下:
加密过程:
a. Xn−1 = Pn−1XOR Cn−2.
b. En−1 = Encrypt (K, Xn−1).
c. Cn = Head (En−1,M).
d. P = Pn || 0B−M.
e. Dn = En−1XOR P.
f. Cn−1 = Encrypt (K, Dn).
解密过程:
a. Dn = Decrypt (K, Cn−1).
b. C = Cn || 0B−M.
c. Xn = DnXOR C.
d. Pn = Head (Xn,M).
e. En−1 = Cn|| Tail (Xn, B−M).
f. Xn−1 = Decrypt (K, En−1).
g. Pn−1 = Xn−1XOR Cn−2.
下面是我绘制的示意图。
按照上文所述,对建立的Win32控制台应用程序进行必要的配置之后(在上篇文章中),就可以开始写程序了。下面就是完成的AES程序。该程序可以去我的资源中找到。
- // aestest2.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include <aes.h>
- #include <cryptopp/Hex.h> // StreamTransformationFilter
- #include <cryptopp/modes.h> // CFB_Mode
- #include <iostream> // std:cerr
- #include <sstream> // std::stringstream
- #include <string>
- using namespace std;
- using namespace CryptoPP;
- #pragma comment( lib, "cryptlib.lib" )
- std::string ECB_AESEncryptStr(std::string sKey, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- ECB_Mode_ExternalCipher::Encryption ecbEncryption(aesEncryption);
- StreamTransformationFilter ecbEncryptor(ecbEncryption, new HexEncoder(new StringSink(outstr)));
- ecbEncryptor.Put((byte *)plainText, strlen(plainText));
- ecbEncryptor.MessageEnd();
- return outstr;
- }
- std::string ECB_AESDecryptStr(std::string sKey, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- ECB_Mode<AES >::Decryption ecbDecryption((byte *)key, AES::MAX_KEYLENGTH);
- HexDecoder decryptor(new StreamTransformationFilter(ecbDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- std::string CBC_AESEncryptStr(std::string sKey, std::string sIV, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);
- StreamTransformationFilter cbcEncryptor(cbcEncryption, new HexEncoder(new StringSink(outstr)));
- cbcEncryptor.Put((byte *)plainText, strlen(plainText));
- cbcEncryptor.MessageEnd();
- return outstr;
- }
- std::string CBC_AESDecryptStr(std::string sKey, std::string sIV, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- CBC_Mode<AES >::Decryption cbcDecryption((byte *)key, AES::MAX_KEYLENGTH, iv);
- HexDecoder decryptor(new StreamTransformationFilter(cbcDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- std::string CBC_CTS_AESEncryptStr(std::string sKey, std::string sIV, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- CBC_CTS_Mode_ExternalCipher::Encryption cbcctsEncryption(aesEncryption, iv);
- StreamTransformationFilter cbcctsEncryptor(cbcctsEncryption, new HexEncoder(new StringSink(outstr)));
- cbcctsEncryptor.Put((byte *)plainText, strlen(plainText));
- cbcctsEncryptor.MessageEnd();
- return outstr;
- }
- std::string CBC_CTS_AESDecryptStr(std::string sKey, std::string sIV, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- CBC_CTS_Mode<AES >::Decryption cbcctsDecryption((byte *)key, AES::MAX_KEYLENGTH, iv);
- HexDecoder decryptor(new StreamTransformationFilter(cbcctsDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- std::string CFB_AESEncryptStr(std::string sKey, std::string sIV, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- CFB_Mode_ExternalCipher::Encryption cfbEncryption(aesEncryption, iv);
- StreamTransformationFilter cfbEncryptor(cfbEncryption, new HexEncoder(new StringSink(outstr)));
- cfbEncryptor.Put((byte *)plainText, strlen(plainText));
- cfbEncryptor.MessageEnd();
- return outstr;
- }
- std::string CFB_AESDecryptStr(std::string sKey, std::string sIV, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- CFB_Mode<AES >::Decryption cfbDecryption((byte *)key, AES::MAX_KEYLENGTH, iv);
- HexDecoder decryptor(new StreamTransformationFilter(cfbDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- std::string OFB_AESEncryptStr(std::string sKey, std::string sIV, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- OFB_Mode_ExternalCipher::Encryption ofbEncryption(aesEncryption, iv);
- StreamTransformationFilter ofbEncryptor(ofbEncryption, new HexEncoder(new StringSink(outstr)));
- ofbEncryptor.Put((byte *)plainText, strlen(plainText));
- ofbEncryptor.MessageEnd();
- return outstr;
- }
- std::string OFB_AESDecryptStr(std::string sKey, std::string sIV, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- OFB_Mode<AES >::Decryption ofbDecryption((byte *)key, AES::MAX_KEYLENGTH, iv);
- HexDecoder decryptor(new StreamTransformationFilter(ofbDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- std::string CTR_AESEncryptStr(std::string sKey, std::string sIV, const char *plainText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- AES::Encryption aesEncryption((byte *)key, AES::MAX_KEYLENGTH);
- CTR_Mode_ExternalCipher::Encryption ctrEncryption(aesEncryption, iv);
- StreamTransformationFilter ctrEncryptor(ctrEncryption, new HexEncoder(new StringSink(outstr)));
- ctrEncryptor.Put((byte *)plainText, strlen(plainText));
- ctrEncryptor.MessageEnd();
- return outstr;
- }
- std::string CTR_AESDecryptStr(std::string sKey, std::string sIV, const char *cipherText)
- {
- std::string outstr;
- //填key
- SecByteBlock key(AES::MAX_KEYLENGTH);
- memset(key,0x30,key.size() );
- sKey.size()<=AES::MAX_KEYLENGTH?memcpy(key,sKey.c_str(),sKey.size()):memcpy(key,sKey.c_str(),AES::MAX_KEYLENGTH);
- //填iv
- byte iv[AES::BLOCKSIZE];
- memset(iv,0x30,AES::BLOCKSIZE);
- sIV.size()<=AES::BLOCKSIZE?memcpy(iv,sIV.c_str(),sIV.size()):memcpy(iv,sIV.c_str(),AES::BLOCKSIZE);
- CTR_Mode<AES >::Decryption ctrDecryption((byte *)key, AES::MAX_KEYLENGTH, iv);
- HexDecoder decryptor(new StreamTransformationFilter(ctrDecryption, new StringSink(outstr)));
- decryptor.Put((byte *)cipherText, strlen(cipherText));
- decryptor.MessageEnd();
- return outstr;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- string plainText = "This Program shows how to use ECB, CBC, CBC_CTS, CFB, OFB and CTR mode of AES in Crypto++.";
- string aesKey = "0123456789ABCDEF0123456789ABCDEF";//256bits, also can be 128 bits or 192bits
- string aesIV = "ABCDEF0123456789";//128 bits
- string ECB_EncryptedText,ECB_DecryptedText,
- CBC_EncryptedText,CBC_DecryptedText,
- CBC_CTS_EncryptedText,CBC_CTS_DecryptedText,
- CFB_EncryptedText,CFB_DecryptedText,
- OFB_EncryptedText,OFB_DecryptedText,
- CTR_EncryptedText,CTR_DecryptedText;
- //ECB
- ECB_EncryptedText = ECB_AESEncryptStr(aesKey, plainText.c_str());//ECB加密
- ECB_DecryptedText = ECB_AESDecryptStr(aesKey,ECB_EncryptedText.c_str());//ECB解密
- //CBC
- CBC_EncryptedText = CBC_AESEncryptStr(aesKey, aesIV, plainText.c_str());//CBC加密
- CBC_DecryptedText = CBC_AESDecryptStr(aesKey, aesIV, CBC_EncryptedText.c_str());//CBC解密
- //CBC_CTS
- CBC_CTS_EncryptedText = CBC_CTS_AESEncryptStr(aesKey, aesIV, plainText.c_str());//CBC_CTS加密
- CBC_CTS_DecryptedText = CBC_CTS_AESDecryptStr(aesKey, aesIV, CBC_CTS_EncryptedText.c_str());//CBC_CTS解密
- //CFB
- CFB_EncryptedText = CFB_AESEncryptStr(aesKey, aesIV, plainText.c_str());//CFB加密
- CFB_DecryptedText = CFB_AESDecryptStr(aesKey, aesIV, CFB_EncryptedText.c_str());//CFB解密
- //OFB
- OFB_EncryptedText = OFB_AESEncryptStr(aesKey, aesIV, plainText.c_str());//OFB加密
- OFB_DecryptedText = OFB_AESDecryptStr(aesKey, aesIV, OFB_EncryptedText.c_str());//OFB解密
- //CTR
- CTR_EncryptedText = CTR_AESEncryptStr(aesKey, aesIV, plainText.c_str());//CTR加密
- CTR_DecryptedText = CTR_AESDecryptStr(aesKey, aesIV, CTR_EncryptedText.c_str());//CTR解密
- cout << "Crypto++ AES-256 加密测试"<< endl;
- cout << "分别使用ECB,CBC, CBC_CTR,CFB,OFB和CTR模式"<< endl;
- cout << "加密用密钥:" << aesKey << endl;
- cout << "密钥长度:" << AES::MAX_KEYLENGTH*8 <<"bits" << endl;
- cout << "IV:" << aesIV << endl;
- cout << endl;
- cout << "ECB测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << ECB_EncryptedText << endl;
- cout << "恢复明文:" << ECB_DecryptedText << endl << endl;
- cout << "CBC测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << CBC_EncryptedText << endl;
- cout << "恢复明文:" << CBC_DecryptedText << endl << endl;
- cout << "CBC_CTS测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << CBC_CTS_EncryptedText << endl;
- cout << "恢复明文:" << CBC_CTS_DecryptedText << endl << endl;
- cout << "CFB测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << CFB_EncryptedText << endl;
- cout << "恢复明文:" << CFB_DecryptedText << endl << endl;
- cout << "OFB测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << OFB_EncryptedText << endl;
- cout << "恢复明文:" << OFB_DecryptedText << endl << endl;
- cout << "CTR测试"<< endl;
- cout << "原文:" << plainText << endl;
- cout << "密文:" << CTR_EncryptedText << endl;
- cout << "恢复明文:" << CTR_DecryptedText << endl << endl;
- getchar();
- return 0;
- }
下面是程序运行结果。可以注意一下各种模式输出的密文长度和具体内容。可以发现ECB和CBC输出模式最长(因要补足128比特块),其他模式输出长度和原文一样。各种模式输出均不相同。