opensslaesdldc

d openssl aes encrypted byte array is not constant between executions


I am linking D to OpenSsl using the Deimos openssl headers for D and am using the ldc 1.8.0 compiler, to try to encrypt a string as a small test. The encrypted byte array isn't consistent with what I would expect. When I run the program and encrypt the string and decrypt it afterwards I get my original string back. But the intermediate encrypted byte array isn't consistent between executions of the code.

So my question is, is this the intended behaviour and does AES in OpenSsl add some kind of salt to the content so it's harder to attack, or is this an error on my part?

import std.stdio;
import std.conv;
import std.string;
import std.outbuffer;

import deimos.openssl.aes;

void main()
{
    writeln("hello world");
    const auto encryption_passphrase = "foo!";

    writeln("The encryption key is \"" ~ encryption_passphrase ~ "\"");

    const auto encryption_content = "bar";
    writeln("The to be encrypted content is: \"" ~ encryption_content ~ "\"");

    writeln("The content lenght is " ~  encryption_content.length.to!string);

    writeln("----------");
    writeln("encrypting");

    AES_KEY encryption_key;

    AES_set_encrypt_key(cast(ubyte*) encryption_passphrase.toStringz, 128, &encryption_key);


    OutBuffer buf = new OutBuffer();
    buf.write(encryption_content);

    ubyte[] inbuffer = buf.toBytes();
    ubyte[] encryptedbuffer = new ubyte[inbuffer.length];
    AES_encrypt(&inbuffer[0], &encryptedbuffer[0], &encryption_key);
    writeln("The encrypted content is: \"" ~ (cast(char*)encryptedbuffer).fromStringz ~ "\"");

    writeln("----------");
    writeln("decrypting");
    AES_KEY decryption_key;
    AES_set_decrypt_key(cast(ubyte*)  encryption_passphrase.toStringz, 128, &decryption_key);

    ubyte[] outbuffer = new ubyte[inbuffer.length];

    AES_decrypt(&encryptedbuffer[0], &outbuffer[0], &decryption_key);
    writeln("the decrypted content is: \"" ~ (cast(char*)outbuffer).fromStringz ~ "\"");
}

Solution

  • The code has several errors on your part.

    First, you seem to confuse a passphrase with a key. Given that you invoke AES_set_encrypt_key() with a key size of 128 bits (the second parameter), the actual bytes used for the key will be the 128 bits = 16 bytes that your first parameter points to. Since your first parameter points to a 0-terminated string "foo!", everything beyond the fifth byte will be unpredictable and the actual key used will possibly be different for each time you run this code.

    Then you want to use the AES_encrypt() function to "encrypt your data" and your data is the 0-terminated string "bar". But that function actually executes operations on blocks of a fixed size of 128 bits = 16 bytes, independent of the key size used. The wikipedia page about AES explains it in detail. So the input and output buffers to that function are both expected to be buffers of 16 bytes. You are giving the function parameters that point to buffers of the wrong size.

    The same problems hold for your "decryption" part of the code.

    Take a look at this concise C example that uses these functions correctly. That might help you getting your code right (and resetting your expectations of what these functions are implemented to do). To achieve what you actually want in the correct way, see the OpenSSL wiki page EVP Symmetric Encryption and Decryption. I have no experience with D programming, but at first sight, the Deimos openssl binding seems to provide all the functionality needed.