Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do AES-128-cbc encryption using nodejs and c separately,using the same key and IV but have different results

I want to use AES-128-cbc encryption/decryption algorithm to encrypt/decrypt some data,and use nodejs to encrypt the data and use c to decrypt them.But found that using the same key and IV,the two languages have different encryption results.See follows:

nodes js code:

var crypto = require('crypto');

var encrypt = function (key, iv, data) {
    var cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
    var crypted = cipher.update(data, 'utf8', 'binary');
    var cbase64  =   new Buffer(crypted, 'binary').toString('base64');
    //console.log(crypted);
    //console.log(cbase64);
    crypted += cipher.final('binary');
    //console.log("hahahaaaaaa:"+crypted.toString('hex'));
    crypted = new Buffer(crypted, 'binary').toString('base64');
    //var c16 = new Buffer(crypted, 'binary').toString(16);
    //console.log(crypted);
    //console.log(c16);

    return crypted;
};

var decrypt = function (key, iv, crypted) {
    crypted = new Buffer(crypted, 'base64').toString('binary');
    var decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
    var decoded = decipher.update(crypted, 'binary', 'utf8');
    //console.log(decoded);
    decoded += decipher.final('utf8');
    //console.log(decoded);
    return decoded;
};

var key='ABCDEFGHIJKLMNOP';
//var iv = new Buffer(crypto.randomBytes(16));
//var iv16 = iv.toString('hex').slice(0,16);
var iv16='0000000000000000';
var fs = require('fs');
fs.readFile('file.txt','utf8',function(err,data){
  console.log(data);
    var encrypted = encrypt(key,iv16,data);
  console.log(encrypted);
   var decrypted = decrypt(key,iv16,encrypted);
  console.log(decrypted);
 fs.writeFile('encrypted.txt',encrypted,function(err){});
});

c codes:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/aes.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
#include <openssl/evp.h>


#define AES_BITS 128
#define MSG_LEN 128


int base64_encode(char *in_str, int in_len, char *out_str)
{
   BIO *b64, *bio;
   BUF_MEM *bptr = NULL;
    size_t size = 0;

     if (in_str == NULL || out_str == NULL)
         return -1;

     b64 = BIO_new(BIO_f_base64());
     bio = BIO_new(BIO_s_mem());
     bio = BIO_push(b64, bio);

     BIO_write(bio, in_str, in_len);
     BIO_flush(bio);

     BIO_get_mem_ptr(bio, &bptr);
     memcpy(out_str, bptr->data, bptr->length);
     out_str[bptr->length] = '\0';
     size = bptr->length;

     BIO_free_all(bio);
     return size;
 }


int aes_encrypt(char* in, char* key, char* out)//, int olen)
{
    if(!in || !key || !out) return 0;
    unsigned char iv[16];
    for(int i=0; i<16; ++i)
        iv[i]='0';
    //printf("size:%d",AES_BLOCK_SIZE);
    //unsigned char *iv = (unsigned char *)"0123456789ABCDEF"; 


    printf("iv: %s\n",iv);
    AES_KEY aes;
    if(AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }
    int len=strlen(in);


    AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_ENCRYPT);
    return 1;
}
int aes_decrypt(char* in, char* key, char* out)
{
    if(!in || !key || !out) return 0;
    unsigned char iv[16];
    for(int i=0; i<16; ++i)
        iv[i]='0';

    //unsigned char *iv = (unsigned char *)"0123456789ABCDEF";    

    AES_KEY aes;
    if(AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
    {
        return 0;
    }
    int len=strlen(in);
    AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT);
    return 1;
}

int main(int argc,char *argv[])
{
    char sourceStringTemp[MSG_LEN];
    char dstStringTemp[MSG_LEN];
    char dstStringTemp_base64[MSG_LEN];
    memset((char*)sourceStringTemp, 0 ,MSG_LEN);
    memset((char*)dstStringTemp, 0 ,MSG_LEN);
    strcpy((char*)sourceStringTemp, "My name is Harlan Chen!");
    //strcpy((char*)sourceStringTemp, argv[1]);
    char key[AES_BLOCK_SIZE]={0};
    int i;
    for(i = 0; i < 16; i++)
    {
        key[i] = 'A' + i;
    }

    printf("keys:%s\n",key);    

    if(!aes_encrypt(sourceStringTemp,key,dstStringTemp))
    {
        printf("encrypt error\n");
        return -1;
    }

    /*To Base64 encrypted data  */
    base64_encode(dstStringTemp, strlen(dstStringTemp),dstStringTemp_base64);    
    printf("Base64 Encrypted data: %s\n",dstStringTemp_base64);

    printf("encrypted:%s\n",dstStringTemp);
    printf("enc %lu:",strlen((char*)dstStringTemp));
    for(i= 0;dstStringTemp[i];i+=1){
        printf("%x",(unsigned char)dstStringTemp[i]);
    }
    memset((char*)sourceStringTemp, 0 ,MSG_LEN);
    if(!aes_decrypt(dstStringTemp,key,sourceStringTemp))
    {
        printf("decrypt error\n");
        return -1;
    }
    printf("\n");
    printf("dec %lu:",strlen((char*)sourceStringTemp));
    printf("%s\n",sourceStringTemp);
    //for(i= 0;sourceStringTemp[i];i+=1){
    //    printf("%x",(unsigned char)sourceStringTemp[i]);
    //}
    printf("\n");
    return 0;
}

nodejs results:

bogon:AES_128_encryption zexu$ node encrypt.js 
My name is Harlan Chen!

jERcWr8ZMzSJcKPGB7RYAYRpMftlThxyZcjfbFYlU3g=
My name is Harlan Chen!

and the c language results:

bogon:AES_128_encryption zexu$ ./a.out 
keys:ABCDEFGHIJKLMNOP
iv: 0000000000000000
Base64 Encrypted data: jERcWr8ZMzSJcKPGB7RYAf6kEOmjJgUksDtrttx4r3k=

encrypted:?D\Z?34?p???X???&$?;k??x?y
enc 32:8c445c5abf1933348970a3c67b4581fea410e9a326524b03b6bb6dc78af79
dec 23:My name is Harlan Chen!

Compare the two base64 strings :

jERcWr8ZMzSJcKPGB7RYAYRpMftlThxyZcjfbFYlU3g=
jERcWr8ZMzSJcKPGB7RYAf6kEOmjJgUksDtrttx4r3k=

The first 21 characters are the same,the following ones are different.I don't know why.

like image 837
Harlan Chen Avatar asked Oct 16 '17 08:10

Harlan Chen


People also ask

What is AES encryption in Java with CBC mode?

Since AES Encryption is an Symmetric algorithm we will be using the same Secret Key for both Encryption as well as Decryption. In this article, we will be discussing about AES (A dvanced E ncryption S tandard ) Symmetric Encryption algorithm in Java with CBC mode ( C ipher B lock C haining). What is AES Encryption?

How many rounds of AES encryption are there in Node JS?

AES uses 10 rounds for 128-bit keys, 12 rounds for 192-bit keys and 14 rounds for 256-bit keys. Each of these rounds uses a different 128-bit round key, which is calculated from the original AES key. Not going deep in AES encryption . Lets discuss how we can encrypt data in node js using AES encryption.

What is AES encryption?

AES stands for Advanced Encryption Standard, a block cipher very commonly used for encrypting data. AES will allow us to easily encrypt some text using a key.

How many bytes are in a 128 bit AES key?

AES treats the 128 bits of a plaintext block as 16 bytes. These 16 bytes are arranged in four columns and four rows for processing as a matrix − Unlike DES, the number of rounds in AES is variable and depends on the length of the key. AES uses 10 rounds for 128-bit keys, 12 rounds for 192-bit keys and 14 rounds for 256-bit keys.


1 Answers

AES is a block cipher, which means, that you always encrypt full blocks of 128 bit (i.e. 16 byte).

Now if you look at your plaintext "My name is Harlan Chen!", you will notice, that these are 23 bytes. This means, that 9 bytes are still left, which is filled with PKCS#7-Padding (9 bytes of value 09) in the nodejs-case, but with zero-bytes in the C case. Furthermore, I suspect there is a trailing newline in the file.txt with your string, which isn't present in the C example, too.

So, you should check with a hex editor, that your string "My name is Harlan Chen!" without a newline and padded with zero bytes up to 32 bytes is inside your file.txt. This will still not yield exactly the same result, since one full block of padding will be added by nodejs (see PKCS#7-Padding) because one byte is always added as padding. But you can disable the automatic padding in your nodejs-script wih

cipher.setAutoPadding(0);

and

decipher.setAutoPadding(0);

Then you should get the same results. As mentioned above, make sure your file.txt does not contain a newline and is padded to 32 bytes with zero-bytes.

Alternatively, you can change your C program to implement PKCS#7 padding; then you should also get the same results. The string to encrypt would be

"My name is Harlan Chen!\x09\x09\x09\x09\x09\x09\x09\x09\x09"

then

like image 171
Ctx Avatar answered Nov 15 '22 09:11

Ctx