Javascript CryptoJS AES-CBC解密十六进制字符串

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-我无法解密加密的有效负载,始终为空字符串“” 我有一种感觉,这两个问题都与内容的格式(十六进制)有关

我目前正在进行一个Arduino/ESP8266项目,该项目需要对特定数据(小字符串)进行AES128加密/解密,该库支持AES256,但目前我将使用AES128。ESP将与Electron/React应用程序接口,该应用程序将解密ESP传输的加密有效载荷。我已将数据解析为十六进制缓冲区,并根据需要拆分数据(iv,加密密钥,hmac,加密数据)

我遇到两个问题: 1-我的HMAC与原件不匹配 2-我无法解密加密的有效负载,始终为空字符串“”

我有一种感觉,这两个问题都与内容的格式(十六进制)有关,因为我已经成功地对“hello123”进行了加密,并使用当前配置再次对其进行解密

有人能看出我做错了什么吗

Javascript解密代码:

// 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());
布雷亚