所以我试图在Objective-C项目中使用Crypto ++加密。 关于如何处理IV的问题?我尝试将它预先附加到密文。但是我在恢复解密时遇到了问题。
以下是代码:
- (NSString *)encryptUsingSerpentWithPlaintext:(NSString *)plaintext andKey:(NSData *)keyData
{
std::string ptext = [plaintext UTF8String];
std::string ciphertext;
byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];
CryptoPP::AutoSeededX917RNG<CryptoPP::Serpent> rng;
rng.GenerateBlock(iv, CryptoPP::Serpent::BLOCKSIZE);
std::string ivs(reinterpret_cast<char const *>(iv));
lcl_log(lcl_cCrypto, lcl_vDebug, @"Random IV:%s",ivs.c_str());
::memcpy(key, keyData.bytes, keyData.length);
CryptoPP::Serpent::Encryption serpentEncryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcSerpentEncryptor (serpentEncryptor, iv);
CryptoPP::StreamTransformationFilter stfSerpentEncryptor(cbcSerpentEncryptor, new CryptoPP::StringSink (ciphertext));
stfSerpentEncryptor.Put( reinterpret_cast<const unsigned char*>( ptext.c_str() ), ptext.length() + 1);
stfSerpentEncryptor.MessageEnd();
lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());
std::string finalCT;
ciphertext = ivs + ciphertext; // add the IV before the ciphertext
lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded iv+ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());
CryptoPP::StringSource base64Encoder (ciphertext, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(finalCT)));
// apply HMAC
// TO DO
NSString *cryptogram = [NSString stringWithUTF8String:finalCT.c_str()];
return cryptogram;
}
- (NSString *)decryptUsingSerpentWithCiphertext:(NSString *)ciphertext andKey:(NSData *)keyData
{
std::string ctext;
std::string plaintext;
byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];
::memcpy(key, keyData.bytes, keyData.length);
// decode from base64
std::string encoded = [ciphertext UTF8String];
CryptoPP::StringSource base64Decoder (encoded, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ctext)));
lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded iv+ciphertext [size:%lu]:%s",sizeof(ctext),ctext.c_str());
// get the IV from the beggining of the cryptogram
std::string ivs = ctext.substr(0,CryptoPP::Serpent::BLOCKSIZE+5);
lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV:%s",ivs.c_str());
::memcpy(iv, &ivs, ivs.size());
// remove the IV from the cryptogram
ctext.erase(0,CryptoPP::Serpent::BLOCKSIZE+5);
lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ctext),ctext.c_str());
CryptoPP::Serpent::Decryption serpentDecryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcSerpentDecryptor (serpentDecryptor, iv);
CryptoPP::StreamTransformationFilter stfSerpentDecryptor(cbcSerpentDecryptor, new CryptoPP::StringSink (plaintext));
stfSerpentDecryptor.Put( reinterpret_cast<const unsigned char*>( ctext.c_str() ), ctext.length());
stfSerpentDecryptor.MessageEnd();
NSString *plainText = [NSString stringWithUTF8String:plaintext.c_str()];
return plainText;
}
注意我需要在预期的iv大小上加5才能获得完整的IV。然后我收到一个错误“无效的PCKS#7填充发现。无效的密文”
如何最好地管理IV? (我还想在iv + ciphertext(Encrypt-then-MAC)中添加一个HMAC ...
如果我这样做:
// get the IV from the beggining of the cryptogram
std::string ivs = ctext.substr(0,CryptoPP::Serpent::BLOCKSIZE);
lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV:%s",ivs.c_str());
::memcpy(iv, &ivs, ivs.size());
// remove the IV from the cryptogram
ctext.erase(0,CryptoPP::Serpent::BLOCKSIZE);
日志将在密文中显示仍有多个IV字节,并生成“无效密文,大小不是blockize的倍数”异常。
日志:
2013-12-01 17:59:37.747 App[413:70b] D Crypto:PSCryptoCore.mm:51:-[PSCryptoCore testSerpentEncryptonMechanism] Initial plaintext:Serpentine and black...
2013-12-01 17:59:37.748 App[413:70b] D Crypto:PSCryptoCore.mm:74:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:ç©ìùËß,¬<ÎΩ9ZÑ0 Û
2013-12-01 17:59:37.749 App[413:70b] D Crypto:PSCryptoCore.mm:87:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Non-Encoded ciphertext [size:4]:PÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.749 App[413:70b] D Crypto:PSCryptoCore.mm:93:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Non-Encoded iv+ciphertext [size:4]:ç©ìùËß,¬<ÎΩ9ZÑ0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.750 App[413:70b] D Crypto:PSCryptoCore.mm:54:-[PSCryptoCore testSerpentEncryptonMechanism] ciphertext:C42pk53opyzCPOu9FDlahDAg8wgBUIOYyO7M0/G0IDG+SZum0+f2qjiKvA4RQm28HaBjCps=
2013-12-01 17:59:37.750 App[413:70b] D Crypto:PSCryptoCore.mm:118:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Non-Encoded iv+ciphertext [size:4]:ç©ìùËß,¬<ÎΩ9ZÑ0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
2013-12-01 17:59:37.752 App[413:70b] D Crypto:PSCryptoCore.mm:123:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Recovered IV:ç©ìùËß,¬<ÎΩ9ZÑ
2013-12-01 17:59:37.753 App[413:70b] D Crypto:PSCryptoCore.mm:131:-[PSCryptoCore decryptUsingSerpentWithCiphertext:andKey:] Non-Encoded ciphertext [size:4]:0 ÛPÉò»ÓÔҥ 1æIõ¶”Áˆ™8äºBmº†c
õ
libc++abi.dylib: terminating with uncaught exception of type CryptoPP::InvalidCiphertext: StreamTransformationFilter: ciphertext length is not a multiple of block size
请注意,在我尝试退出之后,部分IV仍然在密文之前。为什么会这样?
答案 0 :(得分:4)
预先安排IV是完全正确的。为什么要在块大小中添加5?从Base-64解码为数据。将第一个BLOCKSIZE字节作为IV拉出。解密其余部分。
答案 1 :(得分:0)
我设法解决了这个问题。 这是代码
- (NSString *)encryptUsingSerpentWithPlaintext:(NSString *)plaintext andKey:(NSData *)keyData
{
std::string ptext = [plaintext UTF8String];
std::string ciphertext;
byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];
CryptoPP::AutoSeededX917RNG<CryptoPP::Serpent> rng;
rng.GenerateBlock(iv, CryptoPP::Serpent::BLOCKSIZE);
std::string ivs(reinterpret_cast<char const *>(iv));
lcl_log(lcl_cCrypto, lcl_vDebug, @"Random IV:%s",ivs.c_str());
::memcpy(key, keyData.bytes, keyData.length);
CryptoPP::Serpent::Encryption serpentEncryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcSerpentEncryptor (serpentEncryptor, iv);
CryptoPP::StreamTransformationFilter stfSerpentEncryptor(cbcSerpentEncryptor, new CryptoPP::StringSink (ciphertext),CryptoPP::StreamTransformationFilter::BlockPaddingScheme::ONE_AND_ZEROS_PADDING);
stfSerpentEncryptor.Put( reinterpret_cast<const unsigned char*>( ptext.c_str() ), ptext.length() + 1);
stfSerpentEncryptor.MessageEnd();
lcl_log(lcl_cCrypto, lcl_vDebug, @"Non-Encoded ciphertext [size:%lu]:%s",sizeof(ciphertext),ciphertext.c_str());
std::string finalCT;
CryptoPP::StringSource base64Encoder (ciphertext, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(finalCT)));
std::string ivB64;
CryptoPP::StringSource base64IVEncoder (ivs , true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ivB64)));
lcl_log(lcl_cCrypto, lcl_vDebug, @"IV base64[size:%lu]:%s",ivB64.length(),ivB64.c_str());
finalCT = ivB64 + finalCT;
lcl_log(lcl_cCrypto, lcl_vDebug, @"Cryptogram:%s",finalCT.c_str());
// apply HMAC
// TO DO
NSString *cryptogram = [NSString stringWithUTF8String:finalCT.c_str()];
return cryptogram;
}
- (NSString *)decryptUsingSerpentWithCiphertext:(NSString *)ciphertext andKey:(NSData *)keyData
{
std::string ctext;
std::string plaintext;
byte key[ CryptoPP::Serpent::MAX_KEYLENGTH ], iv[ CryptoPP::Serpent::BLOCKSIZE ];
::memcpy(key, keyData.bytes, keyData.length);
// decode from base64
std::string encoded = [ciphertext UTF8String];
// pull IV from ciphertext
std::string ivs = encoded.substr(0,29);
encoded.erase(0,29);
CryptoPP::StringSource base64Decoder (encoded, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ctext)));
std::string iv_tmp;
CryptoPP::StringSource base64IVDecoder (ivs, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(iv_tmp)));
lcl_log(lcl_cCrypto, lcl_vDebug, @"Recovered IV[encoded]:%s",ivs.c_str());
::memcpy(iv, iv_tmp.data(), CryptoPP::Serpent::BLOCKSIZE);
CryptoPP::Serpent::Decryption serpentDecryptor (key, CryptoPP::Serpent::MAX_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcSerpentDecryptor (serpentDecryptor, iv);
CryptoPP::StreamTransformationFilter stfSerpentDecryptor(cbcSerpentDecryptor, new CryptoPP::StringSink (plaintext), CryptoPP::StreamTransformationFilter::BlockPaddingScheme::ONE_AND_ZEROS_PADDING);
stfSerpentDecryptor.Put( reinterpret_cast<const unsigned char*>( ctext.c_str() ), ctext.length());
stfSerpentDecryptor.MessageEnd();
NSString *plainText = [NSString stringWithUTF8String:plaintext.c_str()];
return plainText;
}
我注意到Base64中的IV长度为29 ......我不确定总是这样......对于其他16字节IV,base64字符串的长度是不同的吗?