1

I need to encode some data in c++ and decode it in php, but php is not decoding properly. I checked encoding this same message with the same key and iv, and there is a diference betwen results. This is my code:

struct ctr_state
{
    unsigned char ivec[AES_BLOCK_SIZE];
    unsigned int num;
    unsigned char ecount[AES_BLOCK_SIZE];
};
unsigned char indata[AES_BLOCK_SIZE];
unsigned char outdata[AES_BLOCK_SIZE];
unsigned char iv[AES_BLOCK_SIZE];

struct ctr_state state;

int init_ctr(struct ctr_state *state, const byte iv[16])
{
    /* aes_ctr128_encrypt requires 'num' and 'ecount' set to zero on the
     * first call. */
    state->num = 0;
    memset(state->ecount, 0, AES_BLOCK_SIZE);

    /* Initialise counter in 'ivec' to 0 */
    memset(state->ivec + 8, 0, 8);

    /* Copy IV into 'ivec' */
    memcpy(state->ivec, iv, 8);
}

void aes_encoder(byte *read, byte *write, int size, byte *enc_key, byte *iv)
{
    AES_KEY key;
    if (AES_set_encrypt_key(enc_key, 128, &key) < 0)
    {
       Logger::getInstance()->Error("problem with setting encrypt key");
    }
    init_ctr(&state, iv);

    AES_ctr128_encrypt(read, write, size, &key, state.ivec, state.ecount, &state.num);
}

byte *key = (byte*)"2123456789012345";
byte *iv = (byte*)"2asdasdasdasdasd";

QByteArray message = "this is message";
byte *data = reinterpret_cast<byte *>(message.data());

aes_encoder(data, data,  message.size(), key, iv);
qDebug() << message.toBase64();

the result is: "hF/nlW4e+FmuF8Bfny9M"

and php code:

<?php
$message = "this is message";
$key = "2123456789012345";
$iv = "2asdasdasdasdasd";

$encrypted = openssl_encrypt($message, 'aes-128-ctr', $key, true, $iv);

echo base64_encode($encrypted);

result: "RLLUkP54El9FCeWpO/bI"

Why the results are not the same?

januszmk
  • 145
  • 1
  • 11
  • What is the hard-coded `8` you are using in the line `memset(state->ivec + 8, 0, 8);`? – Floris Jul 28 '13 at 16:43
  • I took this code from here: http://stackoverflow.com/a/3146214/1349417 – januszmk Jul 28 '13 at 16:49
  • Reusing a nonce with CTR mode *completely* breaks the encryption. Every message with a reused nonce can be recovered without knowing the key. Copy-pasting random code off the internet is not the way to write security-related code – you need to precisely understand every little detail. Alternatively, you could use a tried-and-tested library. – ntoskrnl Jul 28 '13 at 17:03

1 Answers1

2

Your problem is that you are not using CTR mode in the standard way. In init_ctr you are only copying 8 bytes of the provided IV and setting the rest to zero. If instead you use the whole IV, you will get the same result as the PHP code:

//don't do this:
//memset(state->ivec + 8, 0, 8);
//memcpy(state->ivec, iv, 8);  

//do this:
memcpy(state->ivec, iv, AES_BLOCK_SIZE);  

The lesson is that just because you found some code somewhere, doesn't mean you can copy-n-paste it without understanding what it is doing. This is especially true with crypto code. If you knew even the basics of what a block cipher is and how one works in CTR mode, you would have realized the problem with your code straightaway.

Oh, important safety tip: When using CTR mode, never encrypt more than one message with the same IV. Or you will die.

zindorsky
  • 1,592
  • 9
  • 9
  • 1
    There's nothing wrong with CTR mode. It's great as long as you don't ever reuse an IV. – zindorsky Jul 28 '13 at 18:31
  • 1
    I should add that there is no such thing as the "best" mode for encryption. It depends on your specific needs. Each one has its strengths and drawbacks. Each one can be used incorrectly by people who don't know what they're doing. – zindorsky Jul 28 '13 at 18:32