Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
AES-128-cbc加密何时分别使用nodejs和c,使用相同的密钥和IV,但结果不同_C_Node.js_Encryption_Aes - Fatal编程技术网

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

AES-128-cbc加密何时分别使用nodejs和c,使用相同的密钥和IV,但结果不同,c,node.js,encryption,aes,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 =

我想用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;
}
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是一种分组密码,这意味着您总是加密128位(即16字节)的完整块

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

因此,您应该使用十六进制编辑器检查您的字符串“My name is Harlan Chen!”是否在file.txt中,该字符串没有换行符且填充了零字节,最多32字节。 这仍然不会产生完全相同的结果,因为nodejs将添加一个完整的填充块(请参见PKCS#7-padding),因为始终添加一个字节作为填充。但是您可以使用以下命令禁用nodejs脚本中的自动填充

cipher.setAutoPadding(0);

那么你应该得到同样的结果。如上所述,请确保file.txt不包含换行符,并用零字节填充到32字节

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

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

那么

这在JS中是什么:
var iv16='0000000000000000'?这是由
'0'
字符(=0x20)组成的字符串还是由
'\0'
字节组成的数组?顺便说一句,您的“加密”不安全。密码必须与消息身份验证代码耦合,否则它们只会对攻击者造成滋扰。@Gerhardh它与C中的IV相同,
0x30303030
。(顺便说一句,
0
实际上是
0x30
,而不是
0x20
,即空格…)两者都是。加密的第一条规则是:“你不推出你自己的加密”。@HarlanChen和例如:)我添加填充,结果是一样的。一个问题。你的解决方案意味着当我使用nodejs加密消息时,我得到了jercwr8zmzzjckpkp7ryayrpmftlthxyzjfbfylu3g=,但当使用c语言解密消息时,我会得到“我叫陈哈兰\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09”,那么我如何知道填充物的长度@Ctx@HarlanChen只要看一下消息的最后一个字节,它总是填充长度,因为填充字节都反映了这个长度。一般的解决方案是使用PKCS#7(有时称为PKCS#5)。
decipher.setAutoPadding(0);
"My name is Harlan Chen!\x09\x09\x09\x09\x09\x09\x09\x09\x09"