Javascript CryptoJS AES-CBC解密十六进制字符串
我目前正在进行一个Arduino/ESP8266项目,该项目需要对特定数据(小字符串)进行AES128加密/解密,该库支持AES256,但目前我将使用AES128。ESP将与Electron/React应用程序接口,该应用程序将解密ESP传输的加密有效载荷。我已将数据解析为十六进制缓冲区,并根据需要拆分数据(iv,加密密钥,hmac,加密数据) 我遇到两个问题: 1-我的HMAC与原件不匹配 2-我无法解密加密的有效负载,始终为空字符串“” 我有一种感觉,这两个问题都与内容的格式(十六进制)有关,因为我已经成功地对“hello123”进行了加密,并使用当前配置再次对其进行解密 有人能看出我做错了什么吗 Javascript解密代码:Javascript CryptoJS AES-CBC解密十六进制字符串,javascript,node.js,cryptography,cryptojs,arduino-esp8266,Javascript,Node.js,Cryptography,Cryptojs,Arduino Esp8266,我目前正在进行一个Arduino/ESP8266项目,该项目需要对特定数据(小字符串)进行AES128加密/解密,该库支持AES256,但目前我将使用AES128。ESP将与Electron/React应用程序接口,该应用程序将解密ESP传输的加密有效载荷。我已将数据解析为十六进制缓冲区,并根据需要拆分数据(iv,加密密钥,hmac,加密数据) 我遇到两个问题: 1-我的HMAC与原件不匹配 2-我无法解密加密的有效负载,始终为空字符串“” 我有一种感觉,这两个问题都与内容的格式(十六进制)有关
// Libraries
import CryptoJS from 'crypto-js';
import { slice } from 'lodash';
testDecryption() {
const input_aesMode128 = '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8F,19,E3,E6,AE,26,93,9F,71,EB,3E,44,17,7C,CE,53,79,15,34,4D,70,C8,6A,E7,7,4B,4F,F6,88,44,ED,E4,2A,40,17,2E,91,DE,D9,3,A2,1B,EF,41,BB,FA,DD,E3,96,1,34,36,E0,60,48,F1,BB,C8,91,A3,4B,91,96,E5';
const input = input_aesMode128;
const parsed = this.splitStringAndParse({ payload: input, delimiter: ',', parseMode: "DECIMAL" });
const aes128hmacPayload = Buffer.from(parsed);
// Extract, parse and store specific data
const ekParsed = this.splitStringAndParse({ payload: '1C,3E,4B,AF,13,4A,89,C3,F3,87,4F,BC,D7,F3,31,31', delimiter: ',', parseMode: 'DECIMAL' });
const ivParsed = this.extractValue({ payload: aes128hmacPayload, startIndex: 0, lengthToExtract: 16 });
const encryptedParsed = this.extractValue({ payload: aes128hmacPayload, startIndex: 16, lengthToExtract: aes128hmacPayload.length - 32 - 16 });
const hmacParsed = this.extractValue({ payload: aes128hmacPayload, startIndex: aes128hmacPayload.length - 32, lengthToExtract: 32 });
// Convert specific data into buffers
const aes128hmacStr = aes128hmacPayload.toString('hex');
const ek = Buffer.from(ekParsed);
const iv = Buffer.from(ivParsed);
const encrypted = Buffer.from(encryptedParsed);
const hmac = Buffer.from(hmacParsed);
// SHA256 of Encryption Key
const shaOfKey = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(ek.toString('hex'))).toString()
console.log({
'Parsed String As Decimal': parsed,
'AES Payload Buffer': aes128hmacPayload,
'AES Payload String': aes128hmacStr,
'Encryption Key': ek.toString('hex'),
'Initialisation Vector': iv.toString('hex'),
'Encrypted Data': encrypted.toString('hex'),
'HMAC': hmac.toString('hex'),
'Encryption Key - keyHash (actually used as the key)': shaOfKey
});
// Calculate HMAC to verify the original
const calculatedHMAC = CryptoJS.HmacSHA256(iv.toString('hex') + encrypted.toString('hex'), shaOfKey).toString();
if (calculatedHMAC === hmac.toString('hex')) {
console.log('HMAC MATCHED!', { original: hmac.toString('hex'), computed: calculatedHMAC });
} else {
console.log('HMAC DOES NOT MATCH!', { original: hmac.toString('hex'), computed: calculatedHMAC });
}
const ivAsHex = CryptoJS.enc.Hex.parse(iv.toString('hex'));
const keyAsHex = CryptoJS.enc.Hex.parse(shaOfKey.toString('hex'));
const options = {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: ivAsHex
};
// const encryptedPayload = CryptoJS.AES.encrypt("hello123", keyAsHex, options);
// console.log({ encrypted: encryptedPayload });
const decryptedPayload = CryptoJS.AES.decrypt(encrypted.toString('hex'), keyAsHex, options);
console.log({ decrypted: decryptedPayload.toString(CryptoJS.enc.Hex) });
},
splitStringAndParse({ payload, delimiter, parseMode }) {
if (parseMode !== 'HEX' && parseMode !== 'DECIMAL' && parseMode !== 'ASCII') {
return new Error('parseMode must either be HEX, ASCII or DECIMAL');
}
const tmp = payload.split(delimiter);
const final = [];
tmp.map(curr => {
const currTmp = parseInt(curr, 16);
switch (parseMode) {
case 'HEX': {
final.push(currTmp.toString(16));
break;
}
case 'DECIMAL': {
final.push(parseInt(currTmp, 10));
break;
}
case 'ASCII': {
final.push(String.fromCharCode(currTmp));
break;
}
default: {
final.push(currTmp);
break;
}
}
});
// return Buffer.from(final);
return final;
},
convertBufferToString({ payload, parseMode }) {
if (parseMode !== 'HEX' && parseMode !== 'DECIMAL' && parseMode !== 'ASCII') {
return new Error('parseMode must either be HEX, ASCII or DECIMAL');
}
let final = '';
payload.map(curr => {
const currTmp = parseInt(curr, 16);
switch (parseMode) {
case 'HEX': {
if (curr < 10) {
final = final.concat('0' + currTmp.toString(16));
} else {
final = final.concat(currTmp.toString(16));
}
break;
}
case 'DECIMAL': {
final = final.concat(currTmp.toString());
break;
}
case 'ASCII': {
final = final.concat(String.fromCharCode(currTmp));
break;
}
default: {
final = final.concat(currTmp.toString());
break;
}
}
});
return final;
},
extractValue({ payload, startIndex, lengthToExtract }) {
// return payload.substring(startIndex, (startIndex + lengthToExtract));
return slice(payload, startIndex, (startIndex + lengthToExtract));
}
#include <Crypto.h> // AES 128 CBC with pkcs7, RNG, SHA256 and SHA256HMAC
#include <base64.hpp> // Base64 encode and decode without line breaks https://github.com/Densaugeo/base64_arduino
/*
* AES encryption with SHA256HMAC on an ESP8266
*/
#define HMAC_KEY_LENGTH 16
#define AES_KEY_LENGTH 16
uint8_t* keyEncrypt;
uint8_t* keyHmac;
uint8_t keyHash[SHA256_SIZE];
uint8_t key[AES_KEY_LENGTH] = { 0x1C,0x3E,0x4B,0xAF,0x13,0x4A,0x89,0xC3,0xF3,0x87,0x4F,0xBC,0xD7,0xF3, 0x31, 0x31 };
uint8_t iv[AES_KEY_LENGTH] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
SHA256 sha256;
// prints given block of given length in HEX
void printBlock(uint8_t* block, int length) {
Serial.print(" { ");
for (int i=0; i<length; i++) {
Serial.print(block[i], HEX);
Serial.print(",");
}
Serial.println(" } ");
}
void setup() {
Serial.begin(115200);
while (!Serial) {
; //wait
}
Serial.printf("\nAES Mode: 128-Bit + SHA256 + HMAC");
Serial.printf("\n\n");
// get SHA-256 hash of our secret key to create 256 bits of "key material"
sha256.doUpdate(key, AES_KEY_LENGTH);
sha256.doFinal(keyHash);
// keyEncrypt is a pointer pointing to the first 128 bits bits of "key material" stored in keyHash
// keyHmac is a pointer poinging to the second 128 bits of "key material" stored in keyHashMAC
keyEncrypt = keyHash;
keyHmac = keyHash + AES_KEY_LENGTH;
Serial.printf("\nkey - (%d bytes)\n", AES_KEY_LENGTH);
printBlock(key, AES_KEY_LENGTH);
Serial.printf("\nkeyHash - sha256 of key\n");
printBlock(keyHash, SHA256_SIZE);
Serial.printf("\nkeyEncrypt - keyHash \n");
printBlock(keyEncrypt, SHA256_SIZE);
Serial.printf("\n");
// maximum packet length for this example is 350 bytes. A crash occurs on larger packets.
char packet[] = "0123456789abcdef\0";
// char packet[] = "1234567890 abcdefghijklmnopqrstuvwxyz !@#$%^&*()_+{|\\:\"<>?-=[];'./,";
// char packet[] = "0123456789abcdef";
Serial.println("\n*** Starting Encryption ***");
int packetSize = strlen(packet);
Serial.printf("\n=> Packet (%d bytes):\n", packetSize);
Serial.println(packet);
Serial.print("\n=> Packet HEX");
printBlock((uint8_t*)packet, packetSize+1); //+1 to add null termination
// random initialization vector
// RNG::fill(iv, AES_KEY_LENGTH);
Serial.printf("\n=> Random IV (%d bytes)", AES_KEY_LENGTH);
printBlock(iv, AES_KEY_LENGTH);
AES aes(keyEncrypt, iv, AES::AES_MODE_128, AES::CIPHER_ENCRYPT);
// create buffer for final message which will contain IV, encrypted message, and HMAC
int encryptedSize = aes.calcSizeAndPad(packetSize);
int ivEncryptedSize = encryptedSize + AES_KEY_LENGTH;
int ivEncryptedHmacSize = ivEncryptedSize + SHA256HMAC_SIZE;
uint8_t ivEncryptedHmac[ivEncryptedHmacSize];
// copy IV to our final message buffer
memcpy(ivEncryptedHmac, iv, AES_KEY_LENGTH);
// encrypted is a pointer that points to the encypted messages position in our final message buffer
uint8_t* encrypted = ivEncryptedHmac + AES_KEY_LENGTH;
// AES 128 CBC and pkcs7 padding
aes.process((uint8_t*)packet, encrypted, packetSize);
Serial.printf("\n=> Encrypted (%d bytes)\n", encryptedSize);
printBlock(encrypted, encryptedSize);
// computedHmac is a pointer which points to the HMAC position in our final message buffer
uint8_t* computedHmac = encrypted + encryptedSize;
// compute HMAC/SHA-256 with keyHmac
SHA256HMAC hmac(keyHmac, HMAC_KEY_LENGTH);
Serial.printf("\n=> ivEncryptedHmac (size %d bytes)\n", ivEncryptedHmacSize);
printBlock(ivEncryptedHmac, ivEncryptedHmacSize);
hmac.doUpdate(ivEncryptedHmac, ivEncryptedSize-32);
hmac.doFinal(computedHmac);
Serial.printf("\n=> Computed HMAC (%d bytes)", SHA256HMAC_SIZE);
printBlock(computedHmac, SHA256HMAC_SIZE);
Serial.printf("\n=> IV | encrypted | HMAC (%d bytes)", ivEncryptedHmacSize);
printBlock(ivEncryptedHmac, ivEncryptedHmacSize);
// base64 encode
int encodedSize = encode_base64_length(ivEncryptedHmacSize); // get size needed for base64 encoded output
uint8_t encoded[encodedSize];
encode_base64(ivEncryptedHmac, ivEncryptedHmacSize, encoded);
Serial.printf("\n=> Base64 encoded to %d bytes\n", encodedSize);
printBlock(encoded, encodedSize);
}
void loop() {
delay(1);
}
//库
从“crypto js”导入CryptoJS;
从“lodash”导入{slice};
testDecryption(){
常量输入法128='0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8F,19,E3,E6,AE,26,93,9F,71,EB,3E,44,17,7C,CE,53,79,15,34,4D,70,C8,6A,E7,4B,4F,F6,88,44,ED,E4,2A,40,17,2E,91,DE,D9,3,A2,1B,EF,41,1B,FA,A3,E3,6A,E7,64,E4,E4,E4,E4,E4,4B,E4,E4,E4,E4,E4,E4,E4,E4,40,40,17,17,21,E4,E4,E4,E4,E4,E4,E4,E4,E4,E4,E;
const input=输入=输入128;
const parsed=this.splitStringAndParse({payload:input,delimiter:',',parseMode:“DECIMAL”});
const aes128hmacPayload=Buffer.from(已解析);
//提取、解析和存储特定数据
const ekParsed=this.splitStringAndParse({有效载荷:'1C,3E,4B,AF,13,4A,89,C3,F3,87,4F,BC,D7,F3,31,31',分隔符:',',parseMode:'DECIMAL'});
const ivParsed=this.extractValue({payload:aes128hmacPayload,startIndex:0,lengthToExtract:16});
const encryptedParsed=this.extractValue({payload:aes128hmacPayload,startIndex:16,lengthToExtract:aes128hmacPayload.length-32-16});
const hmacParsed=this.extractValue({payload:aes128hmacPayload,startIndex:aes128hmacPayload.length-32,lengthToExtract:32});
//将特定数据转换为缓冲区
常量aes128hmacStr=aes128hmacPayload.toString('hex');
const ek=缓冲区from(ekParsed);
const iv=缓冲区from(ivParsed);
const encrypted=Buffer.from(encryptedParsed);
const hmac=Buffer.from(hmacParsed);
//加密密钥的SHA256
const shaOfKey=CryptoJS.SHA256(CryptoJS.enc.Hex.parse(ek.toString('Hex')).toString()
console.log({
“已解析为十进制的字符串”:已解析,
“AES有效负载缓冲区”:aes128hmacPayload,
“AES有效负载字符串”:aes128hmacStr,
“加密密钥”:ek.toString('hex'),
“初始化向量”:iv.toString('hex'),
“加密数据”:加密的.toString('hex'),
'HMAC':HMAC.toString('hex'),
'加密密钥-密钥散列(实际用作密钥)':shaOfKey
});
//计算HMAC以验证原始数据
const calculatedHMAC=CryptoJS.HmacSHA256(iv.toString('hex')+encrypted.toString('hex'),shaOfKey).toString();
if(calculatedHMAC==hmac.toString('hex')){
log('HMAC MATCHED!',{original:HMAC.toString('hex'),computed:calculatedHMAC});
}否则{
log('HMAC不匹配!',{original:HMAC.toString('hex'),computed:calculatedHMAC});
}
const ivAsHex=CryptoJS.enc.Hex.parse(iv.toString('Hex');
const keyAsHex=CryptoJS.enc.Hex.parse(shaOfKey.toString('Hex');
常量选项={
模式:CryptoJS.mode.CBC,
填充:CryptoJS.pad.Pkcs7,
iv:ivAsHex
};
//const encryptedPayload=CryptoJS.AES.encrypt(“hello123”,keyAsHex,options);
//log({加密:encryptedPayload});
const decryptedPayload=CryptoJS.AES.decrypt(encrypted.toString('hex')、keyAsHex、options);
log({decrypted:decryptedPayload.toString(CryptoJS.enc.Hex)});
},
splitStringAndParse({有效负载,分隔符,parseMode}){
if(解析模式!='HEX'&&parseMode!='DECIMAL'&&parseMode!=='ASCII'){
返回新错误('parseMode必须为十六进制、ASCII或十进制');
}
const tmp=payload.split(分隔符);
常量final=[];
tmp.map(curr=>{
const currTmp=parseInt(curr,16);
开关(解析模式){
大小写“HEX”:{
最终推压(电流对弹簧(16));
打破
}
“十进制”大小写:{
推送(parseInt(currTmp,10));
打破
}
案例“ASCII”:{
final.push(String.fromCharCode(currTmp));
打破
}
默认值:{
最终推送(currTmp);
打破
}
}
});
//返回缓冲区。从(最终);
返回最终结果;
},
convertBufferToString({payload,parseMode}){
if(解析模式!='HEX'&&parseMode!='DECIMAL'&&parseMode!=='ASCII'){
返回新错误('parseMode必须为十六进制、ASCII或十进制');
}
让final='';
payload.map(curr=>{
const currTmp=parseInt(curr,16);
开关(解析模式){
大小写“HEX”:{
如果(电流<10){
final=final.concat('0'+电流对串(16));
}否则{
final=final.concat(currTmp.toString(16));
}
打破
}
“十进制”大小写:{
final=final.concat(currTmp.toString());
打破
}
案例“ASCII”:{
final=final.concat(String.fromCharCode(currTmp));
打破
}
默认值:{
final=final.concat(currTmp.toString());
布雷亚