What's the difference between templated mode o

2019-02-26 12:32发布

As in the title, I am looking for the difference in the cryptopp library between this declaration:

CBC_Mode<AES>::Decryption 
cbcDecryption.SetKeyWithIV(key, AES::DEFAULT_KEYLENGTH, iv);

and this one:

AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );

Moreover, I can't understand why with this:

AES::Decryption aesDecryption(key, AES::DEFAULT_KEYLENGTH);
CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );

StreamTransformationFilter stfDecryptor(
    cbcDecryption,
    new StringSink( recoveredtext )
);

stfDecryptor.Put( reinterpret_cast<const unsigned char*>( ciphertext.c_str() ), ciphertext.size() );
stfDecryptor.MessageEnd();

all works fine while using the templated mode I have this error during run time:

AES128CBC: /usr/local/include/cryptopp/misc.h:304: void CryptoPP::memcpy_s(void*, size_t, const void*, size_t): Assertion `dest != __null' failed.
Aborted (core dumped)

Shouldn't be the same?

I have looked at this but I didn't understand well the difference and searching over the net I couldn't find an answer to my problem.

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-02-26 12:54

What's the difference between templated mode object and external cipher object?

The explanation for the *_ExternalCiphers is given in modes.h, and it shows up on the web in CipherModeDocumentation Class Reference. Its not easy to find, and I only know about it because I work closely with the sources.

Here's the text:

Each class derived from this one [CipherModeDocumentation] defines two types, Encryption and Decryption, both of which implement the SymmetricCipher interface. For each mode there are two classes, one of which is a template class, and the other one has a name that ends in "_ExternalCipher".

The "external cipher" mode objects hold a reference to the underlying block cipher, instead of holding an instance of it. The reference must be passed in to the constructor. For the "cipher holder" classes, the CIPHER template parameter should be a class derived from BlockCipherDocumentation, for example DES or AES.

So the difference is how the mode of operation associates with the cipher - literally external versus internal.

External - below are two distinct objects. The first is the symmetric cipher, the second is the mode of operation:

AES::Encryption aes(key, ...);
CBC_Mode_ExternalCipher::Encryption cbc(aes, ...);

Internal - below is a single object. The mode of operation "has a" symmetric cipher that's instantiated through the template:

CBC_Mode<AES>::Encryption enc(key, ...);

all works fine while using the templated mode I have this error during run time...

OK, this is a different problem. Let's see how to use it:

$ grep -IR "CBC_Mode_ExternalCipher::Decryption" *
fipstest.cpp:       KnownAnswerTest(CBC_Mode_ExternalCipher::Encryption(encryption, iv).Ref(), ...);
validat1.cpp:       CBC_Mode_ExternalCipher::Decryption modeD(desD, iv);
validat1.cpp:       CBC_Mode_ExternalCipher::Decryption modeD(desD, iv);
validat1.cpp:       CBC_Mode_ExternalCipher::Decryption modeD(desD, iv);
validat1.cpp:       CBC_Mode_ExternalCipher::Decryption modeD(desD, iv);

You can find validat1.cpp online, starting around line 1366:

bool ValidateCipherModes()
{
    ...
    DESEncryption desE(key);
    DESDecryption desD(key);

    ...
    CBC_Mode_ExternalCipher::Encryption modeE(desE, iv);
    ...
    CBC_Mode_ExternalCipher::Decryption modeD(desD, iv);
    ...
}

So the wild card is DESEncryption and DESDecryption. Let's see about it:

$ grep -IR DESEncryption *
des.h:typedef DES::Encryption DESEncryption;

So AES should cut-in cleanly. Now, the test program:

#include "filters.h"
#include "osrng.h"
#include "modes.h"
#include "files.h"
#include "aes.h"
using namespace CryptoPP;

#include <iostream>
#include <string>
using namespace std;

// g++ -DNDEBUG -g2 -O2 -I. test.cxx ./libcryptopp.a -o test.exe
int main(int argc, char* argv[])
{
  AutoSeededRandomPool prng;
  string plain = "Now is the time for all good men to come to the aide of their country";
  string cipher, recover;

  SecByteBlock key(AES::DEFAULT_KEYLENGTH), iv(AES::BLOCKSIZE);
  prng.GenerateBlock(key, key.size());
  prng.GenerateBlock(iv, iv.size());

  AES::Encryption aes1(key, key.size());
  CBC_Mode_ExternalCipher::Encryption cbc1(aes1, iv);
  StringSource ss1(plain, true, new StreamTransformationFilter(cbc1, new StringSink(cipher)));

  AES::Decryption aes2(key, key.size());
  CBC_Mode_ExternalCipher::Decryption cbc2(aes2, iv);
  StringSource ss2(cipher, true, new StreamTransformationFilter(cbc2, new StringSink(recover)));

  cout << "Plain: " << plain << endl;
  cout << "Recover: " << recover << endl;

  return 0;
}

Compile and run:

$ g++ -DNDEBUG -g2 -O2 -I. test.cxx ./libcryptopp.a -o test.exe
$

$ ./test.exe
Plain: Now is the time for all good men to come to the aide of their country
Recover: Now is the time for all good men to come to the aide of their country

So everything appears to be working as expected.


Now, for this issue:

AES128CBC: /usr/local/include/cryptopp/misc.h:304: void CryptoPP::memcpy_s(void*, size_t, const void*, size_t):
Assertion `dest != __null' failed.

In AES128 in CBC mode implementation using cryptopp library, you were told to use the latest Crypto++ library because we cleaned up a few of them. See this comment:

You should use the latest version of the Crypto++ sources. I believe this issue was cleared some time ago: void CryptoPP::memcpy_s(void*, size_t, const void*, size_t): Assertion 'dest != __null' failed. You can get the latest sources with a git clone https://github.com/weidai11/cryptopp.git.

You also accepted Zaph's answer, so that should be the end of things with respect to you troubles with decryption and the assert. That signaled to me and the Stack Overflow community you did not need additional help or answers.

The problem you are likely running into is mixing your version of Crypto++ located at /usr/local with the one you installed via your distro with sudo apt-get install libcrypto++-dev libcrypto++-doc libcrypto++-utils. The assert is a classic sign of mixing and matching them because the distro provides an old version of the library.

If you take note of the command line I used, you will see:

  • -DNDEBUG -g2 -O2 to ensure I'm using the same options as used to build the library
  • -I to ensure I'm using the Crypto++ headers in PWD
  • ./libcryptopp.a to ensure I link to the static version of the library in PWD and avoid runtime linking/loading with the wrong library

You are probably runtime linking with the wrong Crypto++ library. I avoid them by controlling exactly what is linked, and not depending on the runtime link/loader.


You are free to use the runtime link/loader to do these things, but care must be taken to ensure you get the right library at runtime. For that, see GNUmakefile | Compiling and Linking. I think you are in the second case called out as BAD:

Bad: the following will create problems because you compile and link against your copy of the library, but at runtime it links to the distro's copy of the library:

$ ls
cryptopp        test.cxx

$ g++ -DNDEBUG -g2 -O2 -I . test.cxx -o test.exe -L ./cryptopp -lcryptopp

If its not solved, then you need to post a Minimal, Complete, and Verifiable example (MCVE). It could well be that an assert fires under your data set. We had one recently at Trying to do CMAC on VS2013 and found this error. "Assertion failed: (input && length) || !(input || length)". We checked-in the fix within hours of the report, which is less than 30 days ago.

I also need to see your compile and link command, and the output of ldd to see what you are linking against.

Sometimes, there's nothing we can do when you don't provide the plain text or cipher text data (input0.txt and output0.txt), or you don't provide details like the compile and link command.

查看更多
登录 后发表回答