我正在使用新协议进行安全通信,而我在解密密文方面遇到了问题。
数据包保存在uint8_t *变量中并加密。直到这部分一切顺利。但是当我尝试解密时,我遇到了以下问题:
1)如果我发送矢量和大小(它真的是20但我只想解密最后16个字节):
CBC_Mode< AES >::Decryption decryptor;
decryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
CryptoPP::StringSource ss( vector+4, 16 , true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
我明白了:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
2)如果我只是发送没有大小的矢量:
CryptoPP::StringSource ss( vector+4, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
程序运行但我得到全部00:
Text Encrypted (20 bytes)
8c 97 b7 d8 74 80 3d 9f 9f 62 2e 93 38 c7 d1 b de a4 21 80
Text Decrypted (16 bytes)
0 0 0 0 0 0 0 0 68 0 0 0 0 0 0 0 0 0 0 0
我读到可能是密钥没有正确生成,但我的工作大小为16,这就是我的工作方式:
byte key[ CryptoPP::AES::DEFAULT_KEYLENGTH ], iv[ CryptoPP::AES::BLOCKSIZE ];
memset( key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH );
memset( iv, 0x00, CryptoPP::AES::BLOCKSIZE );
3)我还尝试将矢量转换为char并将其发送为字符串:
CryptoPP::StringSource ss( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ) ) );
但我再次得到同样的结论:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
请帮助,我已经试了好几天才弄明白什么是错的。这花了我太长时间,我找不到解决方案。
有没有人知道可能发生的事情?
如果您需要更多详细信息,代码或任何内容,请与我们联系。
编辑:
4)我尝试的另一件事是(构建解密器的另一种方法):
CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );
CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink( decryptedtext ) );
stfDecryptor.Put( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16 );
stfDecryptor.MessageEnd();
但我也是这样:
terminate called after throwing an instance of 'CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
EDIT2:
使用此行创建向量(向量填充的方式非常复杂,因为我使用的是网络编码平台):
uint8_t* vector;
EDIT3:
这就是我加载矢量的方式。
CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption( aesEncryption, iv );
CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink( ciphertext ) );
stfEncryptor.Put( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16 );
stfEncryptor.MessageEnd();
然后我将密文重新放入向量中:
std::cout << std::endl << std::endl;
for(int i=0;i < 16; i++){
*(vector+ i + 4) = (ciphertext[i]) ;
}
答案 0 :(得分:3)
terminate called after throwing an instance of CryptoPP::InvalidCiphertext'
what(): StreamTransformationFilter: invalid PKCS #7 block padding found
这很容易修复。捕获Crypto ++ InvalidCiphertext
异常。请参阅InvalidCiphertext Class Reference。
If I just send the vector without size:
CryptoPP::StringSource ss( vector+4, true, ...
我认为这可能与以下StringSource
构造函数匹配,这意味着长度为true
,这可能意味着1.为了增加对伤害的侮辱,所附StreamTransformationFilter
被强制进入bool pumpAll
:
StringSource (const byte *string, size_t length, bool pumpAll, BufferedTransformation *attachment=NULL)
你应该启用警告来捕捉这些事情。 -Wall -Wextra
是不错的选择。 (但是,没有任何东西可以帮助强制指向bool
的指针。例如,请参阅GCC邮件列表中的No pointer conversion warning for "bool" in C/C++。
If I send the vector and the size (it's really 20 but I
just want to decrypt the last 16 bytes):
...
CryptoPP::StringSource ss( vector+4, 16 , true, ...
我认为这不会按预期工作。 CBC模式不是随机访问模式(但我可能无法正确解析):
CBC_Mode< AES >::Encryption enc;
cout << "Random access: " << enc.IsRandomAccess() << endl;
结果:
Random access: 0
我相当肯定它不会以字节大小工作。您可以通过在解密器上方添加一个层来实现,但是您必须管理初始化向量,然后解密一个块,最后将offest返回到块中。
您应该执行以下操作。它效率不高,因为它处理string
到vector
,但我想尝试使用向量,因为你似乎正在使用它们。
encrypted.CopyTo(f2)
是放置套接字代码的地方。您的代码不需要encrypted.CopyTo(f2)
。
// Creates the memory block and zero's it.
SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
/////////////////////////////////////////////////////////////
string m1;
vector<char> v1;
m1 = "Now is the time for all good men to come to the aide of their country";
copy(m1.begin(), m1.end(), back_inserter(v1));
CBC_Mode< AES >::Encryption enc;
enc.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue encrypted;
StreamTransformationFilter f1(enc, new Redirector(encrypted));
f1.PutWord32((uint32_t)v1.size(), BIG_ENDIAN_ORDER);
f1.Put((const unsigned char *) &v1[0], v1.size());
f1.MessageEnd();
/////////////////////////////////////////////////////////////
string m2;
vector<char> v2;
CBC_Mode< AES >::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue decrypted;
StreamTransformationFilter f2(dec, new Redirector(decrypted));
encrypted.CopyTo(f2);
f2.MessageEnd();
uint32_t len;
decrypted.GetWord32(len, BIG_ENDIAN_ORDER);
v2.resize(len);
decrypted.Get((unsigned char *) &v2[0], v2.size());
copy(v2.begin(), v2.end(), back_inserter(m2));
/////////////////////////////////////////////////////////////
cout << "Message: " << m1 << endl;
cout << "Decrypted: " << m2 << endl;
它产生了预期的结果:
$ ./cryptopp-test.exe
Message: Now is the time for all good men to come to the aide of their country
Decrypted: Now is the time for all good men to come to the aide of their country
关于vector + 4
的使用:一旦密文被解密,你可以在其中搜索,并做一些事情,比如从中读取长度。这就是它的作用:
// Ciphertext is already decrypted
uint32_t len;
decrypted.GetWord32(len, BIG_ENDIAN_ORDER);
如果您只想丢弃该值,请尝试:
decrypted.Skip(4);
但是,您必须弄清楚如何调整vector
的大小。
我正在使用新协议进行安全通信
安全通信通常提供机密性和真实性保证。你似乎错过了后者,因为CBC模式只提供机密性。
使用已经存在的东西可能是个好主意,比如IPSec(首选)或TLS(将在紧要关头)。此外,关键协议将是一个痛点。它是考虑使用IPSec或TLS之类的另一个原因。
如果您无法使用已有的内容,则应使用Authenticated Encryption模式,以便将机密性和真实性合并为一种模式。尝试EAX,GCM或CCM模式。
如果你这样做,那么改变就相当简单:
EAX< AES >::Encryption enc;
enc.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue encrypted;
AuthenticatedEncryptionFilter f1(enc, new Redirector(encrypted));
和
EAX< AES >::Decryption dec;
dec.SetKeyWithIV(key, key.size(), iv, iv.size());
ByteQueue decrypted;
AuthenticatedDecryptionFilter f2(dec, new Redirector(decrypted));
您可以通过将密文复制到编码器来打印密文。复制是非破坏性的(与使用TransferTo
移动它不同):
string encoded;
HexEncoder encoder(new StringSink(encoded));
encrypted.CopyTo(encoder);
encoder.MessageEnd();
Fox CBC模式(不太安全):
Encrypted: 7F9FFCAB00704EC79BB5F19C48FE7C668033B16F52E7E00671A38A06F4A7426E7FE31
95CA6A83C7414A76C250B42E63143C93E7A6B97B6304C5782DE3E62BD545706A9F62CD7AD57BC374
19B7510EBED
对于EAX模式(更安全):
Encrypted: B75347EB75DF8E1F0424979E91CEECD455F5727B506A8AA932AF07E1DF6A7B037A245
FEC7A2270BFAB8110226769E1C0A12E95C455E9C714AF28DA330A2B01B3F2D541D4E68276193C018
7BA0246166AD26624E848EC8330D3
EAX模式中的额外字节是身份验证标记。它用于检测意外和恶意篡改。
答案 1 :(得分:0)
问题是我使用padding进行编码并试图在没有填充的情况下对其进行解密。所以我不仅在加密中添加,而且在解密中添加它应该在没有填充的情况下工作。
创建密钥和IV:
CBC_Mode< AES >::Encryption encryptor;
encryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
加密:
CryptoPP::StringSource ss( vector + 4 , 16, true,
new CryptoPP::StreamTransformationFilter( encryptor,
new CryptoPP::StringSink( ciphertext ),
CryptoPP::StreamTransformationFilter::NO_PADDING
) // StreamTransformationFilter
); // StringSource
解密:
CBC_Mode< AES >::Decryption decryptor;
decryptor.SetKeyWithIV( key, CryptoPP::AES::DEFAULT_KEYLENGTH, iv );
CryptoPP::StringSource ss( reinterpret_cast<const unsigned char*>( (vector + 4) ), 16, true,
new CryptoPP::StreamTransformationFilter( decryptor,
new CryptoPP::StringSink( decryptedtext ), CryptoPP::StreamTransformationFilter::NO_PADDING) );
我这样做是因为我不想再使用填充。