我想使用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个字符是相同的,以下是不同的。我不知道为什么。
答案 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"
然后