c++ - 如何在多次应用于输入的crypto++中实现AES?哪种AES模式?
问题描述
对于我的目标应用程序,我想为给定的输入连续多次使用 AES。在连续加密它 $i$ 次后,如果向后解密 $i$ 次,它应该会产生相同的起始输入。
给定一些示例代码,我已经实现了一些可行的解决方案:
//g++ -o aestest aestest.cpp -lcryptopp
#include <iostream>
#include <iomanip>
#include "cryptopp/modes.h"
#include "cryptopp/aes.h"
#include "cryptopp/filters.h"
#include <cassert>
void dispBA(std::vector<byte> &bav, std::string text =""){
std::cout << text << " : size "<< bav.size() <<" byte"<< std::endl;
for( long unsigned int i = 0; i < bav.size(); i++ ) {
std::cout << std::dec<< (int)((static_cast<byte>(bav[i]))) << ", ";
}
std::cout << std::endl << std::endl;
}
void encryptBV(CryptoPP::CBC_Mode_ExternalCipher::Encryption &cbcEncryption, std::vector<byte> &bytesIn, std::vector<byte> &bytesCrypOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::ArraySink( &bytesCrypOut[0],bytesCrypOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfEncryptor.Put( &bytesIn[0], bytesIn.size() );
stfEncryptor.MessageEnd();
if(disp)dispBA(bytesCrypOut, "Cipher numbers");
}
void decryptBV(CryptoPP::CBC_Mode_ExternalCipher::Decryption &cbcDecryption, std::vector<byte> &bytesCrypIn, std::vector<byte> &bytesDecrOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::ArraySink( &bytesDecrOut[0], bytesDecrOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfDecryptor.Put( &bytesCrypIn[0], bytesCrypIn.size() );
stfDecryptor.MessageEnd();
if(disp)dispBA(bytesDecrOut, "Decrypted numbers");
}
int main(int argc, char* argv[]) {
//Key 32 bytes -> aes256
//block size always 16
const int myKeysize = 32;
byte key[ myKeysize ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, myKeysize ); // no key set yet
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
//encryption
std::vector<byte> bytesCryp(myKeysize);
CryptoPP::AES::Encryption aesEncryption(key, myKeysize);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
//decryption
std::vector<byte> bytesDecr(myKeysize);
CryptoPP::AES::Decryption aesDecryption(key, myKeysize);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
std::vector<byte> bytesIn = {0 ,1, 2, 3, 4, 5 ,6 ,7 ,8 ,9 ,10 ,11, 12, 13 ,14 ,15 ,16, 17, 18 ,19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30,31};
assert(bytesIn.size()== myKeysize);
dispBA(bytesIn, "Starting number");
//-----does work for single en/decryption
// Create Cipher numbers
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
// Decrypt
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
int count = 42;
for(int i=0; i < count; i++){
cbcEncryption.SetKeyWithIV(key, myKeysize, iv ); // ++
encryptBV(cbcEncryption, bytesIn, bytesCryp);
cbcEncryption.SetKeyWithIV(key, myKeysize, iv ); // ++
encryptBV(cbcEncryption, bytesCryp, bytesIn);
}
for(int i=0; i<count; i++){
cbcDecryption.SetKeyWithIV(key, myKeysize, iv ); // ++
decryptBV(cbcDecryption, bytesIn, bytesCryp);
cbcDecryption.SetKeyWithIV(key, myKeysize, iv ); // ++
decryptBV(cbcDecryption, bytesCryp, bytesIn);
}
dispBA(bytesIn, "end"); // this does only return the correct value if lines marked with ++ are added
//-----but it does also work if I repeat them without changing the inputs--- ["W2"]
// Create Cipher numbers
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
//encryptBV(cbcEncryption, bytesIn, bytesCryp, true);
// Decrypt
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
//decryptBV(cbcDecryption, bytesCryp, bytesDecr, true);
return 0;
}
但是,目前这仅在我在每条消息后重置密钥(或生成新的 ExternalCipher)时才有效。尽管密钥仅在单个(128,196,256 位)消息(或长消息内)的轮次中更改,并且不会继续通过消息。
有一个更好的方法吗?或者如果我不更改输入,为什么会发生这种情况并且不会发生(参见[“W2”])?
在这里,我发现了不同的操作模式。我猜这些是AES的不同实现。我应该使用某个吗?(编辑:欧洲央行?它不支持 afaik)
解决方案
crypto++ 操作模式中没有列出 ECB 模式,但是!crypto++ 在这里显示了一些我可以做一些小的重写:
//ecb
void encryptBV(CryptoPP::ECB_Mode< CryptoPP::AES >::Encryption &ecbEncryption, std::vector<byte> &bytesIn, std::vector<byte> &bytesCrypOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfEncryptor(ecbEncryption, new CryptoPP::ArraySink( &bytesCrypOut[0],bytesCrypOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfEncryptor.Put( &bytesIn[0], bytesIn.size() );
stfEncryptor.MessageEnd();
if(disp)dispBA(bytesCrypOut, "Cipher number");
}
void decryptBV(CryptoPP::ECB_Mode< CryptoPP::AES >::Decryption &ecbDecryption, std::vector<byte> &bytesCrypIn, std::vector<byte> &bytesDecrOut, bool disp=false){
CryptoPP::StreamTransformationFilter stfDecryptor(ecbDecryption, new CryptoPP::ArraySink( &bytesDecrOut[0], bytesDecrOut.size() ), CryptoPP::StreamTransformationFilter::NO_PADDING );
stfDecryptor.Put( &bytesCrypIn[0], bytesCrypIn.size() );
stfDecryptor.MessageEnd();
if(disp)dispBA(bytesDecrOut, "Decrypted number");
}
int main(int argc, char* argv[]) {
//Key 32 bytes -> aes256
//block size always 16
const int myKeysize = 32;
byte key[ myKeysize ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, myKeysize ); // no key set yet
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
CryptoPP::ECB_Mode< CryptoPP::AES >::Encryption ecbEncryption;
ecbEncryption.SetKey( key, myKeysize);
CryptoPP::ECB_Mode< CryptoPP::AES >::Decryption ecbDecryption;
ecbDecryption.SetKey( key, myKeysize);
std::vector<byte> bytesCryp(myKeysize);
std::vector<byte> bytesDecr(myKeysize);
std::vector<byte> bytesIn = {0 ,1, 2, 3, 4, 5 ,6 ,7 ,8 ,9 ,10 ,11, 12, 13 ,14 ,15 ,16, 17, 18 ,19 ,20 ,21 ,22 ,23 ,24 ,25 ,26 ,27 ,28 ,29 ,30,31};
dispBA(bytesIn, "Starting number");
//test single encrypt, decrypt
encryptBV(ecbEncryption, bytesIn, bytesCryp, true);
decryptBV(ecbDecryption, bytesCryp, bytesDecr, true);
int count = 42;
for(int i=0; i<count; i++){
encryptBV(ecbEncryption, bytesIn, bytesCryp);
encryptBV(ecbEncryption, bytesCryp, bytesIn);
}
for(int i=0; i<count; i++){
decryptBV(ecbDecryption, bytesIn, bytesCryp);
decryptBV(ecbDecryption, bytesCryp, bytesIn);
}
dispBA(bytesIn, "end");
}
它的运行速度也更快(约 60%)。
警告:这对于正常的 AES 使用来说是不安全的。
(如果其他人找到更好的方法,我可以更改正确答案)
推荐阅读
- javascript - 如何从字符串中提取最大的数字?
- android - 如何修复 JobScheduler(不是调度任务)
- python - 从 df 动态更新 Dash 数据表
- python - Azure App Services:停止站点 MYSITE,因为它在启动期间失败
- c# - 无法打开登录请求的数据库用户 C# 的登录失败
- java - Java Socket 数据包拦截
- python - Python Pandas:为 2 个分类变量的唯一组合创建变量?
- flutter - ItemList 中的 ItemList 不滚动
- reactjs - AWS Amplify Storage.get 函数中的 useEffect 内存泄漏
- node.js - 在 Mongoose 方法上使用 bcrypt 时出现 UnhandledPromiseRejectionWarning