c - 分别使用nodejs和c做AES-128-cbc加密时,使用相同的key和IV但结果不同

标签 c node.js encryption aes

我想用AES-128-cbc加密/解密算法加密/解密一些数据,用nodejs加密数据用c解密,但是发现使用相同的key和IV,两种语言有不同的加密结果。见下图:

Node 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个字符一样,后面的不一样,不知道为什么。

最佳答案

AES 是一种 block 密码,这意味着您始终加密 128 位(即 16 字节)的完整 block 。

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

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

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"

然后

关于c - 分别使用nodejs和c做AES-128-cbc加密时,使用相同的key和IV但结果不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46766115/

相关文章:

c - 你如何制作内存和数据结构的图表?

c - 反向冒泡排序保留头寸索引?

函数声明或函数原型(prototype)会影响程序的运行吗

node.js - 通过条件将 Firebase 云消息传递 (FCM) 发送到多个主题的正确语法是什么

node.js - 谷歌 OAuth 2 "accessNotConfigured"错误

具有 base 64 + hMac 编码的 iOS 应用程序

c# - 如何使用 RSACryptoServiceProvider 解密加密文本?

c - 向量化具有间接访问的循环

javascript - node.js(javascript)中的系统范围互斥锁

c - EVP_PKEY_keygen() 将 key 对生成为字符串?