Initialization-Vector

來自 Crypto++ AutoSeedRNG 的 IV 總是以相同的方式結束:PRNG 有問題嗎?

  • May 28, 2014

I am using a AutoSeededRNG from Crypto++ to generate IVs for use in CBC encryption.

I am encoding the IVs using Base64 for future use (decryption).

I notice that all the Base64 encoded IVs end with gB. Why is this? Is it a security problem?

Here is the code:

for (int i = 0; i < 10; i++) {
   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());

   std::string ivB64;
   ivs.erase(std::remove(ivs.begin(), ivs.end(), '\n'), ivs.end());


   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());


   std::string encoded;

   CryptoPP::StringSource ss(ivs, true,
                   new CryptoPP::HexEncoder(
                                  new CryptoPP::StringSink(encoded)
                                  ) // HexEncoder
                   ); // StringSource

   lcl_log(lcl_cCrypto, lcl_vDebug, @"IV hex[size:%lu]:%s",encoded.length(),encoded.c_str());


}

Here are the logs:

2013-12-02 21:28:31.616 app[8043:70b] D Crypto:PSCryptoCore.mm:83:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:À’àà·Ùº@‹œ©$"˜Ó0VÊ
2013-12-02 21:28:31.617 app[8043:70b] D Crypto:PSCryptoCore.mm:91:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV base64[size:29]:y9WIiOH0vEDcz6kkESL37jBW5ggB
2013-12-02 21:28:31.617 app[8043:70b] D Crypto:PSCryptoCore.mm:102:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV hex[size:42]:CBD58888E1F4BC40DCCFA9241122F7EE3056E60801
2013-12-02 21:28:31.618 app[8043:70b] D Crypto:PSCryptoCore.mm:83:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:8À⁄    $]Q#:u   ‚»ëʪ0VÊ
2013-12-02 21:28:31.618 app[8043:70b] D Crypto:PSCryptoCore.mm:91:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV base64[size:29]:OMvaDSRdUSM6dQniyJHmuzBW5ggB
2013-12-02 21:28:31.619 app[8043:70b] D Crypto:PSCryptoCore.mm:102:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV hex[size:42]:38CBDA0D245D51233A7509E2C891E6BB3056E60801
2013-12-02 21:28:31.619 app[8043:70b] D Crypto:PSCryptoCore.mm:83:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:\^Ê(U%‰◊ΩΩ+ÿ0VÊ
2013-12-02 21:28:31.619 app[8043:70b] D Crypto:PSCryptoCore.mm:91:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV base64[size:29]:XANe5ihVJRrk1729HSsR2DBW5ggB
2013-12-02 21:28:31.620 app[8043:70b] D Crypto:PSCryptoCore.mm:102:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV hex[size:42]:5C035EE62855251AE4D7BDBD1D2B11D83056E60801
2013-12-02 21:28:31.620 app[8043:70b] D Crypto:PSCryptoCore.mm:83:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:Eo(æ`¨ösˇ ?‡ˆäFÿ0VÊ
2013-12-02 21:28:31.621 app[8043:70b] D Crypto:PSCryptoCore.mm:91:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV base64[size:29]:RW8ovmCsmnP/DT/g9opG2DBW5ggB
2013-12-02 21:28:31.621 app[8043:70b] D Crypto:PSCryptoCore.mm:102:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV hex[size:42]:456F28BE60AC9A73FF0D3FE0F68A46D83056E60801
2013-12-02 21:28:31.622 app[8043:70b] D Crypto:PSCryptoCore.mm:83:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] Random IV:)ø´èÏ˙.êu\ø=uk®ä0VÊ
2013-12-02 21:28:31.622 app[8043:70b] D Crypto:PSCryptoCore.mm:91:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV base64[size:29]:Kb+rj+z6LpB1XL89dWuoijBW5ggB
2013-12-02 21:28:31.623 app[8043:70b] D Crypto:PSCryptoCore.mm:102:-[PSCryptoCore encryptUsingSerpentWithPlaintext:andKey:] IV hex[size:42]:29BFAB8FECFA2E90755CBF3D756BA88A3056E60801

At first I believed it had something to do with the newline character and removed that, but the gB at the end stayed. If I concatenate the IV to the ciphertext any attacker will know where the IV is based on that gB. Apparently it’s also in the HEX… Maybe it has something to do with the StringSource?

The hexadecimal output of an IV matching the block size of Serpent should be 32 characters. Since you are getting 42, that is an extra 5 bytes of data. The last 5 bytes of every IV you posted is 3056E60801, which leads me to strongly believe this is an implementation issue, possibly related to reinterpret_cast.

In terms of the RNG itself, it appears to be ok, although at first glance there appears to be a stronger bias towards B and 8 in the hex output, which may indicate a problem. Larger quantities of RNG output would be needed to detect bias. You may want to generate more RNG data (40 bytes or so) and then pass it to a cryptographic hash to generate IVs.

The easy fix here is to truncate the generated IV to 16 bytes before use, but that may cause an issue if the program is expecting 21 bytes for whatever reason.

Another fix (and method I use) is to prepend the IV to the plaintext before encrypting, then passing an all 0 IV to the encryption class. During decryption the first output block is simply ignored. This allows the IV to be stored with the encrypted data in an encrypted format, and is at least as secure as storing the IV in plaintext and using it in the normal method. The IV must be the block length for this to work as expected.

This question is about artifacts produced by buggy debug code written in C++, and squarely off-topic; but I can’t vote to close it (I tried), because there is a bounty.

IMHO the problem is: char const * is not the appropriate type for a pointer to an arbitrary collection of bytes of some length, like an IV is. The thing pointed-to by a char const * is a C string, that is a collection of non-zero bytes, up to the next 0 byte (conventionally: not included in the length of the C string), which location determines the length of the thing.

Thus, after std::string ivs(reinterpret_cast<char const *>(iv)); the object ivs contains a copy of the bytes forming the object iv and whatever bytes happen to be in memory after that, up to the first 0 byte in iv or said memory. Possibly the IV (in the cryptographic sense) is at the beginning of that, unless of course it contains a 0 (a real possibility). We’d need to know the details of type iv to ascertain that, but they are not given.

假設這一點,我們之後得到ivs的任何東西都是以人類可讀的形式重新解釋(可能是部分的)IV 以及之後的任何額外內容。

引用自:https://crypto.stackexchange.com/questions/12077