何时使用nodejs和c进行AES-128-cbc加密,使用相同的密钥和IV但结果不同

时间:2017-10-16 08:38:08

标签: c node.js encryption aes

我想使用AES-128-cbc加密/解密算法来加密/解密某些数据,并使用nodejs加密数据并使用c来解密它们。但是发现使用相同的密钥和IV,这两种语言有不同的加密结果。参见:

节点js代码:

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代码:

#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结果:

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

jERcWr8ZMzSJcKPGB7RYAYRpMftlThxyZcjfbFYlU3g=
My name is Harlan Chen!

和c语言结果:

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!

比较两个base64字符串:

jERcWr8ZMzSJcKPGB7RYAYRpMftlThxyZcjfbFYlU3g=
jERcWr8ZMzSJcKPGB7RYAf6kEOmjJgUksDtrttx4r3k=

前21个字符是相同的,以下是不同的。我不知道为什么。

1 个答案:

答案 0 :(得分:3)

AES是密码,这意味着您总是加密128位的完整块(即16字节)。

现在,如果你看一下你的明文“我的名字是Harlan Chen!”,你会注意到这些是23个字节。这意味着,仍剩下9个字节,在nodejs-case中填充了PKCS#7-Padding(值为09的9个字节),但在C情况下为零字节。此外,我怀疑file.txt中有一个带有你的字符串的尾随换行符,在C语例中也没有。

所以,您应该使用十六进制编辑器检查您的字符串“我的名字是Harlan Chen!”没有换行符,填充零字节,最多32个字节在file.txt中。 这仍然不会产生完全相同的结果,因为nodejs将添加一个完整的填充块(参见PKCS#7-Padding),因为总是添加一个字节作为填充。但您可以在nodejs-script中禁用自动填充

cipher.setAutoPadding(0);

decipher.setAutoPadding(0);

然后你应该得到相同的结果。如上所述,请确保您的file.txt不包含换行符,并使用零字节填充为32个字节。

或者,您可以更改C程序以实现PKCS#7填充;那么你也应该得到相同的结果。要加密的字符串是

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

然后