CryptoJS AES-CBC Расшифровка шестнадцатеричных строк - PullRequest
0 голосов
/ 06 мая 2018

В настоящее время я работаю над проектом Arduino / ESP8266, который требует шифрования / дешифрования определенных данных (небольших строк) AES128, библиотека поддерживает AES256, но сейчас я получу 128 рабочих. 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));
    }

ESP8266 Код эскиза Arduino:

#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);
}
...