微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

WebCrypto API:DOMException:提供的数据太小

如何解决WebCrypto API:DOMException:提供的数据太小

我想使用在后端加密的 react.js (Web Crypto API) 在客户端 (node.js) 解密消息,但是我遇到了一个奇怪的问题并且不知道出了什么问题(我还检查了 this

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','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 是什么用法,需要在客户端解密吗?

解决方法

GCM 是经过身份验证的加密。解密需要认证标签。用于检查密文的真实性,只有在确认后才进行解密。
由于该标签未应用于您的 WebCrypto 代码,因此身份验证和解密失败。

WebCrypto 期望将标签附加到密文:ciphertext |标签

以下代码中的数据是使用您的 NodeJS 代码创建的(请注意 NodeJS 代码中存在一个错误:密钥存储在 output 中而不是 IV):

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。