Вопрос

Ok I hate doing this but I am getting frustrated because there is little to no documentation on the CBC_CTS_Mode_ExternalCipher .

I have a partially known key for AES128. I built a function to generate all possible combinations and permutations of the unknown and known parts of the key. Let me rephrase that... sorry, the function creates a key in the format that I am wanting, that is 16 bytes of hex, but the output of the decryption is all messed up I was going to just decrypt the message and XOR for CBC manually but I do not have the time.

When the decryption outputs I get all sorts of symbols, numbers, letters and crazyness.

string ciphertext = "C7A4123420BF4EFFB815BC0EA8B46D00F440D068CDD9BB28860DC3E9B312710743";
string plaintext;

CryptoPP::AES::Decryption aesDecryption(tmp, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_CTS_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv );

CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new 
    CryptoPP::StringSink( plaintext ) );

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

Can someone with more knowledge help explain why this is not working or explain a better way of decrypting a ciphertext string in CBC mode when you already have the ciphertext for cryptanalysis?

Thanks

EDIT: Replaced "The key works but the decryption doesnt", with Let me rephrase that... sorry, the function creates a key in the format that I am wanting, that is 16 bytes of hex, but the output of the decryption is all messed up

Это было полезно?

Решение

a better way of decrypting a ciphertext string in CBC mode when you already have the ciphertext for cryptanalysis

You are using CTS mode, not CBC mode. So the first step is to use the correct mode ;)

Here's an example of CBC encryption and decryption from the Crypto++ wiki CBC Mode:

AutoSeededRandomPool prng;

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

byte iv[ AES::BLOCKSIZE ];
prng.GenerateBlock( iv, sizeof(iv) );

string plain = "CBC Mode Test";
string cipher, encoded, recovered;

/*********************************\
\*********************************/

try
{
    cout << "plain text: " << plain << endl;

    CBC_Mode< AES >::Encryption e;
    e.SetKeyWithIV( key, key.size(), iv );

    // The StreamTransformationFilter adds padding
    //  as required. ECB and CBC Mode must be padded
    //  to the block size of the cipher.
    StringSource ss( plain, true, 
        new StreamTransformationFilter( e,
            new StringSink( cipher )
        ) // StreamTransformationFilter      
    ); // StringSource
}
catch( const CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

/*********************************\
\*********************************/

// Pretty print cipher text
StringSource ss( cipher, true,
    new HexEncoder(
        new StringSink( encoded )
    ) // HexEncoder
); // StringSource
cout << "cipher text: " << encoded << endl;

/*********************************\
\*********************************/

try
{
    CBC_Mode< AES >::Decryption d;
    d.SetKeyWithIV( key, key.size(), iv );

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource ss( cipher, true, 
        new StreamTransformationFilter( d,
            new StringSink( recovered )
        ) // StreamTransformationFilter
    ); // StringSource

    cout << "recovered text: " << recovered << endl;
}
catch( const CryptoPP::Exception& e )
{
    cerr << e.what() << endl;
    exit(1);
}

Here's a typical output:

$ ./driver.exe 
key: B00DDF9D93E199EFEAE967805E0A5228
iv: CA8A8878F145C9B9B3C31A1F15C34A6D
plain text: CBC Mode Test
cipher text: D6AF39534926C21CFF3E7477A7146FF3
recovered text: CBC Mode Test

string ciphertext = "C7A4123420BF4EFFB815BC0EA8B46D00F440D068CDD9BB28860DC3E9B312710743"

The second thing you will probably want to do is change that string from hexadecimal encoded to binary. That's covered in the Crypto++ wiki under HexDecoder:

string encoded = "FFEEDDCCBBAA99887766554433221100";
string decoded;

StringSource ss(encoded,
    new HexDecoder(
        new StringSink(decoded)
    ) // HexDecoder
); // StringSource

After the above code runs, you will have a binary string with possibly embedded NULLs. So be sure to use decoded.data() for the pointer, and decoded.size() for the length of the binary string.


When the decryption outputs I get all sorts of symbols, numbers, letters and crazyness.

That could mean decryption has failed. The only way to really tell is if you supply an authentication tag like an HMAC over the cipher text. Otherwise, you will get those results.

If you use a mode that requires padding (like CBC mode), then you will still get spurious hits when the padding happens to be correct. The only unambiguous way to tell is to provide an authentication tag.


I built a function to generate all possible combinations and permutations of the unknown and known parts of the key.

You should show that routine too in case it has an error. We can't comment on the way you are permuting bits, but we can comment on whether it looks like its producing a binary string as Crypto++ uses.


I was going to just decrypt the message and XOR for CBC manually but I do not have the time.

I really don't know what to make of this... Do you want to operate AES in ECB mode and then perform the XOR yourself? If so, you might consider an ArrayXorSink.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top