2

I have been using the Encryption/Decryption code from https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption.

The NIST test vectors (http://csrc.nist.gov/groups/STM/cavp/) for AES don't yield the expected result. May I know what could be the reason and how do I get it going to work according to NIST test vectors?

For readability I will add the code below:#include

#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>


int main(int arc, char *argv[])
{
/* Set up the key and iv. Do I need to say to not hard code these in a
* real application? :-)
*/

/* A 256 bit key */
unsigned char ***key** = "0000000000000000000000000000000000000000000000000000000000000000";

/* A 128 bit IV */
unsigned char ***iv** = "00000000000000000000000000000000";

/* Message to be encrypted */
unsigned char *plaintext =
"80000000000000000000000000000000";

/* Buffer for ciphertext. Ensure the buffer is long enough for the
 * ciphertext which may be longer than the plaintext, dependant on the
 * algorithm and mode
 */
unsigned char ciphertext[128];

/* Buffer for the decrypted text */
unsigned char decryptedtext[128];

int decryptedtext_len, ciphertext_len;

/* Initialise the library */
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);

/* Encrypt the plaintext */
ciphertext_len = encrypt(plaintext, strlen(plaintext), key, iv,
ciphertext);

/* Do something useful with the ciphertext here */
printf("Ciphertext is:\n");
BIO_dump_fp(stdout, ciphertext, ciphertext_len);

/* Decrypt the ciphertext */
decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
decryptedtext);

/* Add a NULL terminator. We are expecting printable text */
decryptedtext[decryptedtext_len] = '\0';

/* Show the decrypted text */
printf("Decrypted text is:\n");
printf("%s\n", decryptedtext);

/* Clean up */
EVP_cleanup();
ERR_free_strings();

return 0;
}

void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext)
{
EVP_CIPHER_CTX *ctx;

int len;

int ciphertext_len;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

/* Initialise the encryption operation. IMPORTANT - ensure you use a key
 * and IV size appropriate for your cipher
 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 * IV size for *most* modes is the same as the block size. For AES this
 * is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();

/* Provide the message to be encrypted, and obtain the encrypted output.
 * EVP_EncryptUpdate can be called multiple times if necessary
 */
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;

/* Finalise the encryption. Further ciphertext bytes may be written at
 * this stage.
 */
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
ciphertext_len += len;

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

return ciphertext_len;
}

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
unsigned char *iv, unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;

int len;

int plaintext_len;

/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

/* Initialise the decryption operation. IMPORTANT - ensure you use a key
 * and IV size appropriate for your cipher
 * In this example we are using 256 bit AES (i.e. a 256 bit key). The
 * IV size for *most* modes is the same as the block size. For AES this
 * is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();

/* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
handleErrors();
plaintext_len = len;

/* Finalise the decryption. Further plaintext bytes may be written at
 * this stage.
 */
if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
plaintext_len += len;

/* Clean up */
EVP_CIPHER_CTX_free(ctx);

return plaintext_len;
}

The output that I get is :

Ciphertext is:

0000 - 0d d2 52 e5 3c 69 ad 57-f2 93 1c 2b 0b 1b 84 a6 ..R.

0010 - 3e c8 b7 ca c5 67 65 82-16 df ac 51 cc ae d7 20 >....ge....Q...

0020 - 6a 2a 39 fd 8f f9 2a b7-e5 6d 27 47 c5 36 ef 65 j*9...*..m'G.6.e

Decrypted text is:

80000000000000000000000000000000

But according to NIST Test Vector, the output should be : ddc6bf790c15760d8d9aeb6f9a75fd4e

  • 2
    This might be related: OpenSSL fails NIST AES-128-ECB test vectors? – StackzOfZtuff Apr 10 '15 at 7:11
  • @StackzOfZtuff, Firstly, Thank you :-). Coming to the post, I saw the post that you have referred to and tried all the vector types - KAT, MCT, Intermediate MMT and MMT but to no success. It is not according to NIST test vectors. – RSH Apr 10 '15 at 8:45
  • Can you explain what portion is failing? Is it encrypting correctly at all? Can you post the output you expect vs. the output you get? – RoraΖ Apr 10 '15 at 11:32
  • @raz I have edited the post containing the details (key, IV, plain text, cipher text(obtained) & cipher text(expected)) – RSH Apr 10 '15 at 12:06
4

I haven't tested OpenSSL but I'm pretty sure it implements AES-CBC correctly. Your program, however, obviously uses different data, so it isn't surprising that you get different results.

The test vectors are given out in hexadecimal. For example

KEY = 0000000000000000000000000000000000000000000000000000000000000000
IV = 00000000000000000000000000000000
PLAINTEXT = 80000000000000000000000000000000
CIPHERTEXT = ddc6bf790c15760d8d9aeb6f9a75fd4e

has a 32-byte key (the right size for AES-256) in which all bytes have the value 0. Similarly the 16-byte IV has all bytes 0, the plaintext consists in a byte with the value 0x80=128 followed by 15 bytes with the value 0, and the ciphertext is the given 16-byte string.

Your program is using data which in the NIST notation is

KEY = 3030303030303030303030303030303030303030303030303030303030303030
IV = 30303030303030303030303030303030
PLAINTEXT = 38303030303030303030303030303030

That is, you key consists of 64 bytes each of which is the ASCII code of the character 0, etc.

The result of your calculation is correct, by the way (by which I mean the output you posted is correct for the data in your program). However there are several things you should note about sizes which would matter in a real program. Your key variable contains a 65-byte array (64 bytes 0x30=48='0' (digit zero) plus a terminating null byte) — this works because the computation only uses the first 32 bytes of the array but makes the program confusing. The same applies to the IV. For the plaintext, you calculate the length with strlen; keep in mind that this only works if the data doesn't contain any null byte, so it works if your data is a C string but not for arbitrary binary data. You list 48 bytes of output, but you fed 32 bytes of input, so the output is actually only 32 bytes.

In case you're confused about the output size: each input block in CBC encryption yields one output block. In practice, the output from CBC encryption is larger because it doesn't just contain the output of the CBC algorithm, for two reasons. First, the IV is usually sent as a prefix to the ciphertext, so there is an extra block at the beginning of the ciphertext which is the IV. In other words, a “CBC encrypted message” usually consists of the IV followed by the actual output of the CBC algorithm. Second, CBC only specifies how to encrypt data whose size is a multiple of the block size (16 bytes for AES regardless of key size). So to encrypt arbitrary-sized data, you need to apply a padding algorithm to get a whole number of blocks, and then apply CBC to the result of the padding algorithm. The OpenSSL functions that you use apply PKCS#7 padding (a common choice), resulting in the output size being rounded up to a whole number of blocks, or, when the input size is a whole number of blocks, one extra output blocks. To summarize:

              CBC
32 bytes ------------> 32 bytes

           PKCS#7 padding                CBC                 preprend IV
32 bytes -----------------> 48 bytes -----------> 48 bytes ---------------> 64 bytes
  • Thanks a ton! I am a newbie. Sorry for the ignorance. Could you please tell me what tweak in the code is required to get the requisite cipher text according to NIST? – RSH Apr 13 '15 at 5:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.