3

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.

Community
  • 1
  • 1
aterpin
  • 110
  • 1
  • 9
  • 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 Mar 26 '16 at 19:01
  • 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 Mar 26 '16 at 19:45
  • 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 Mar 26 '16 at 20:27
  • If the decryption has padding specified it will be noticed that the padding is incorrect. See [PKCS7](https://en.wikipedia.org/wiki/Padding_(cryptography)#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 Mar 26 '16 at 21:12
  • 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 Mar 26 '16 at 21:28
  • Yes, see my answer (answer for formatting). With PKS#7 padding specified on decryption the adding is removed automatically. – zaph Mar 26 '16 at 21:43
  • 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`*. – jww Mar 27 '16 at 10:57
  • It occurred to me... You might also want to consider CCM, GCM or EAX mode (or the upcoming OCB mode addition). Also see [Authenticated Encryption](http://www.cryptopp.com/wiki/Authenticated_Encryption) on the Crypto++ wiki. – jww Mar 29 '16 at 12:43

2 Answers2

2

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]);
zaph
  • 111,848
  • 21
  • 189
  • 228
  • I decoded from hex to ASCII your result removing the IV (16 bytes) and the result is the correct answer, can I ask you how did you coded the decryption? Or better where did I go wrong in my code? – aterpin Mar 26 '16 at 21:44
  • Corrected answer, I picked the version that included the iv. – zaph Mar 26 '16 at 21:47
  • I use a different language and library (Common Crypto) so my code will not help. Basically provide the correct inputs and you will get the correct output, it is just a function. My guess is that you are not supplying the input(s) in the correct format. The library I use is simply data based so there is little guessing. The reason you are getting a padding error is not the padding but that the decryption is wrong, the way the parameters are supplied. – zaph Mar 26 '16 at 21:52
  • Hint for debugging (only): set no padding on the decryption and they you will be able to see the padding, PKCS#7 padding is easy to recognize. – zaph Mar 26 '16 at 21:55
  • Yes, thank you, the problem was in the ct input: I didn't convert it from hex to ascii. Now all works fine. – aterpin Mar 26 '16 at 22:39
1

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;
}
aterpin
  • 110
  • 1
  • 9