3
votes

In the input file I have:
on the first line a key which is encoded in hex and with length of 16 bytes;
on the second line encrypted message ( AES128 in CBC mode , with a random iv prepended to the encrypted message).

This is how I tried to decrypt:

#include<iostream>
using namespace std;

#include <fstream>
#include <string.h>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>

using namespace CryptoPP;

int main(void) {
    ifstream in("input0.txt");
    ofstream out("output0.txt");

    string hex_key = "", hex_ct = "";
    in >> hex_key >> hex_ct;

    byte key[ AES::DEFAULT_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
    string ciphertext = "", recoveredtext = "";

    for(int i = 0; i < hex_key.size(); i+=2) {
        key[i/2] = (char) strtol((hex_key.substr(i, 2)).c_str(), 0, 16);
    }

    //then I divide iv from the text
    for(int i = 0; i < AES::BLOCKSIZE*2; i+=2) {
        iv[i/2] = (char) strtol((hex_ct.substr(i, 2)).c_str(), 0, 16);
    }

    for(int i = AES::BLOCKSIZE*2; i < hex_ct.size(); i++) {
        ciphertext.push_back(hex_ct[i]);
    }

    //decryption
    CBC_Mode< AES >::Decryption d;
    d.SetKeyWithIV(key, AES::DEFAULT_KEYLENGTH, iv);

    StringSink sink( recoveredtext );

    StreamTransformationFilter stf (
        d,
        &sink
    );

    StringSource ss (
        ciphertext,
        true,
        &stf
    );

    out << recoveredtext;

    return 0;
}

I used this implementation following the Wiki.
I also tried with this and it worked, but not replacing key and ciphertext with my.
Well, using the code above I have this output:

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)

While using this code:

//decryption

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

StreamTransformationFilter stfDecryptor(
    cbcDecryption,
    new StringSink( recoveredtext ),
    BlockPaddingSchemeDef::NO_PADDING
);

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

It works but the output isn't a valid sequence of characters.

I installed the lib with:

sudo apt-get install libcrypto++-dev libcrypto++-doc libcrypto++-utils

and I compiled it with:

g++ -o AESCBC128 AESCBC128.cpp -lcryptopp

I can't find what's wrong.
Thanks in advance for the help.

Sample of input:

140b41b22a29beb4061bda66b6747e14
4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81


I don't know a sample of output because this is an exercise and my goal is to discover the secret message.
Test on the inputs and on conversion to byte arrays:

out << "KEY:\n" << hex_key << endl;

for(int i = 0; i < AES::DEFAULT_KEYLENGTH; i++) {
    out << setfill('0') << setw(2) << hex << (int)key[i];
}

out << endl << "Received message:\n" << hex_ct << endl;

out << "IV:\n";
for(int i = 0; i < AES::BLOCKSIZE; i++) {
    out << setfill('0') << setw(2) << hex << (int)iv[i];
}

out << endl << "CT:\n" << ciphertext << endl;

Result:

KEY:
140b41b22a29beb4061bda66b6747e14
140b41b22a29beb4061bda66b6747e14
Received message:
4ca00ff4c898d61e1edbf1800618fb2828a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81
IV:
4ca00ff4c898d61e1edbf1800618fb28
CT:
28a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81

They are as expected.

2
Debug the code. You forgot sample data and inputs/utpots. Print the key, iv, encrypted data, expected decrypted data preferably in hex. Are they correct? Test with short input data. Is the encryption using PKCS#7 padding, the decryption is expecting PKCS#7 padding. - zaph
I edited the question with an input and with some test, they are correct. About the padding, is the decryption influenced by the pad? Sorry, this is my first time with cryptopp and this is also my first question in stackoverflow. - aterpin
Ok, adding in the StreamTransformationFilter constructor the block padding scheme parameter (NO_PADDING), the second code works, but the output is a no-sense sequence of characters. I'm sure about the inputs, what went wrong? - aterpin
If the decryption has padding specified it will be noticed that the padding is incorrect. See PKCS7. The error may occur from an incorrect key, different padding during encryption (mcrypt I'm looking at you) or no padding during encryption. Some implementations will not report padding errors because it is really useless and such an error should not be propagated back to the caller in any form in order to avoid a padding oracle attach. - zaph
Suppose the length of the message is 40: then i would have a pad of 8 bytes '8' appended to the original plaintext.. Well the pad is decrypted as part of the plaintext, right? Then at the end I have to remove from the recovered text a number of bytes which is described in the last byte of the recovered text. Am I right? If it is, then with "no padding" as padding scheme I should decrypt correctly the pad appended to the plaintext, so then I can remove it and gain only the secret message. Right? If it is, is probably that the input is not correct? Or how can I solve this padding problem? - aterpin

2 Answers

2
votes

A probable reason you are getting a padding error is not the padding but that the decryption is wrong, the way the parameters are supplied is probably incorrect.

I coded up decryption on the supplied KEY, IV and CT. The result has PKCS#7 padding of 8 bytes of 0x08.

(correct to remove iv)

Decryption with padding removed:

42617369 63204342 43206d6f 64652065 6e637279 7074696f 6e206e65 65647320 70616464 696e672e

or in text:

Basic CBC mode encryption needs padding.

Decryption with padding intact (note the trailing 8 characters of padding):

42617369 63204342 43206d6f 64652065 6e637279 7074696f 6e206e65 65647320 70616464 696e672e 08080808 08080808

The output is mostly ASCII with a few exceptions such as the 3rd byte 0xfc.

Because the padding is correct I believe this is the true data that was encrypted.

For the overly curious here is my test code:

NSData *key    = [Utilities dataFromHexString:@"140b41b22a29beb4061bda66b6747e14"];
NSData *iv     = [Utilities dataFromHexString:@"4ca00ff4c898d61e1edbf1800618fb28"];
NSData *dataIn = [Utilities dataFromHexString:@"28a226d160dad07883d04e008a7897ee2e4b7465d5290d0c0e6c6822236e1daafb94ffe0c5da05d9476be028ad7c1d81"];

size_t         cryptBytes = 0;
NSMutableData *dataOut    = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeAES128];

CCCrypt(kCCDecrypt,
        kCCAlgorithmAES,
        kCCOptionPKCS7Padding,
        key.bytes, key.length,
        iv.bytes,
        dataIn.bytes, dataIn.length,
        dataOut.mutableBytes, dataOut.length,
        &cryptBytes);
dataOut.length = cryptBytes;

NSLog(@"dataOut: %@", dataOut);
NSLog(@"dataOut: %@", [[NSString alloc] initWithData:dataOut encoding:NSUTF8StringEncoding]);
1
votes

Yes, the problem was in the input: I didn't convert the ciphertext from hex to ascii.

So the solution is to use this:

for(int i = AES::BLOCKSIZE*2; i < hex_ct.size(); i+=2) {
        ciphertext.push_back((char) strtol((hex_ct.substr(i, 2)).c_str(), 0, 16));
    } 

Instead of this:

for(int i = AES::BLOCKSIZE*2; i < hex_ct.size(); i++) {
        ciphertext.push_back(hex_ct[i]);
    }

The IV and the PAD are automatically removed.

So the solution code is:

#include<iostream>
using namespace std;

#include <fstream>
#include <string.h>
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include <cryptopp/filters.h>

using namespace CryptoPP;

int main(void) {
    ifstream in("input0.txt");
    ofstream out("output0.txt");

    string hex_key = "", hex_ct = "";
    in >> hex_key >> hex_ct;

    byte key[ AES::DEFAULT_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
    string ciphertext, recoveredtext;

    for(int i = 0; i < hex_key.size(); i+=2) {
        key[i/2] = (char) strtol((hex_key.substr(i, 2)).c_str(), 0, 16);
    }

    for(int i = 0; i < AES::BLOCKSIZE*2; i+=2) {
        iv[i/2] = (char) strtol((hex_ct.substr(i, 2)).c_str(), 0, 16);
    }

    for(int i = AES::BLOCKSIZE*2; i < hex_ct.size(); i+=2) {
        ciphertext.push_back((char) strtol((hex_ct.substr(i, 2)).c_str(), 0, 16));
    }

    //decryption

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

    out << recoveredtext;

    return 0;
}