WebCrypto API: DOMException: предоставленные данные слишком малы

Я хочу расшифровать сообщение на стороне клиента (react.js), используя Web Crypto API, который зашифрован на бэкэнде (node.js), однако я столкнулся со странной проблемой и понятия не имею, что не так (я также проверил это)

node.js

function encrypt(message){
    const KEY = crypto.randomBytes(32)
    const IV = crypto.randomBytes(16)
    const ALGORITHM = 'aes-256-gcm';
    const cipher = crypto.createCipheriv(ALGORITHM, KEY, IV);
    let encrypted = cipher.update(message, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    const tag = cipher.getAuthTag()
    let output = {
        encrypted,
        KEY: KEY.toString('hex'),
        IV: KEY.toString('hex'),
        TAG: tag.toString('hex'),
     }
    return output;
}

react.js

function decrypt() {
let KEY = hexStringToArrayBuffer(data.KEY);
let IV = hexStringToArrayBuffer(data.IV);
let encrypted = hexStringToArrayBuffer(data.encrypted);
let TAG = hexStringToArrayBuffer(data.TAG);

window.crypto.subtle.importKey('raw', KEY, 'AES-GCM', true, ['decrypt']).then((importedKey)=>{
  window.crypto.subtle.decrypt(
    {
      name: "AES-GCM",
      iv: IV,
    },
    importedKey,
    encrypted
  ).then((plaintext)=>{
    console.log('plainText: ', plaintext);
  })
})

function hexStringToArrayBuffer(hexString) {
  hexString = hexString.replace(/^0x/, '');
  if (hexString.length % 2 != 0) {
    console.log('WARNING: expecting an even number of characters in the hexString');
  }
  var bad = hexString.match(/[G-Z\s]/i);
  if (bad) {
    console.log('WARNING: found non-hex characters', bad);    
  }
  var pairs = hexString.match(/[\dA-F]{2}/gi);
  var integers = pairs.map(function(s) {
    return parseInt(s, 16);
  });
  var array = new Uint8Array(integers);
  return array.buffer;
} 

Шифрование в серверной части выполняется без ошибок, однако, когда я хочу расшифровать сообщение на стороне клиента, браузер (chrome) выдает эту ошибку: DOMException: The provided data is too small и когда я запускаю программу на firefox выдает ошибку: DOMException: The operation failed for an operation-specific reason. Это так непонятно!!

Кстати, какое использование athentication tag в AES-GCM необходимо для расшифровки на стороне клиента?


person Shahin Ghasemi    schedule 11.02.2021    source источник


Ответы (1)


GCM — это шифрование с проверкой подлинности. Тег аутентификации необходим для расшифровки. Он используется для проверки подлинности зашифрованного текста, и только когда это подтверждено, выполняется дешифрование.
Поскольку тег не применяется в вашем коде WebCrypto, аутентификация и, следовательно, дешифрование не выполняются.

WebCrypto ожидает, что тег будет добавлен к зашифрованному тексту: ciphertext | тег.

Данные в приведенном ниже коде были созданы с использованием вашего кода NodeJS (обратите внимание, что в коде NodeJS есть ошибка: вместо IV ключ хранится в output):

decrypt();
 
function decrypt() {

    let KEY = hexStringToArrayBuffer('684aa9b1bb4630f802c5c0dd1428403a2224c98126c1892bec0de00b65cc42ba');
    let IV = hexStringToArrayBuffer('775a446e052b185c05716dd1955343bb');
    let encryptedHex = 'a196a7426a9b1ee64c2258c1575702cf66999a9c42290a77ab2ff30037e5901243170fd19c0092eed4f1f8';
    let TAGHex = '14c03526e18502e4c963f6055ec1e9c0';
    let encrypted = hexStringToArrayBuffer(encryptedHex + TAGHex)

    window.crypto.subtle.importKey(
        'raw', 
        KEY,
        'AES-GCM', 
        true, 
        ['decrypt']
    ).then((importedKey)=> {
        window.crypto.subtle.decrypt(
            {
                name: "AES-GCM",
                iv: IV,
            },
            importedKey,
            encrypted
        ).then((plaintext)=>{
            console.log('plainText: ', ab2str(plaintext));
        });
    });
}

function hexStringToArrayBuffer(hexString) {
    hexString = hexString.replace(/^0x/, '');
    if (hexString.length % 2 != 0) {
        console.log('WARNING: expecting an even number of characters in the hexString');
    }
    var bad = hexString.match(/[G-Z\s]/i);
    if (bad) {
        console.log('WARNING: found non-hex characters', bad);    
    }
    var pairs = hexString.match(/[\dA-F]{2}/gi);
    var integers = pairs.map(function(s) {
        return parseInt(s, 16);
    });
    var array = new Uint8Array(integers);
    return array.buffer;
} 

function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint8Array(buf));
}

person user 9014097    schedule 11.02.2021