自定义解密:超出最大调用堆栈大小

时间:2019-03-04 05:59:05

标签: javascript angular ionic-framework

问题

我目前遇到以下错误:RangeError: Maximum call stack size exceeded,该错误发生在代码部分下面概述的行上。

当我尝试解密从我的API返回的一堆数据时,似乎发生了这种情况,因为我创建的服务中抛出了错误。

奇怪的是,当我对较小的数据调用该方法时,它的工作没有问题。下面提到的ApiService的解密方法在代码部分下面概述,这是专门导致错误的部分。

希望你们能帮上忙,因为很奇怪,它只能处理少量数据,但不能处理大量数据。


堆栈跟踪

ERROR Error: Uncaught (in promise): RangeError: Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at ApiService.<anonymous> (api.service.ts:167)
    at step (tslib.es6.js:97)
    at Object.next (tslib.es6.js:78)
    at fulfilled (tslib.es6.js:68)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
    at Object.onInvoke (core.js:17298)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:150)
    at zone.js:889
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at resolvePromise (zone.js:831)
    at zone.js:741
    at rejected (tslib.es6.js:69)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
    at Object.onInvoke (core.js:17298)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:390)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.run (zone.js:150)
    at zone.js:889
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17289)

数据

正在传递给以下概述方法的数据如下:

Data: "PHAl4fGtOUPM9Rop5P0eG1f1L9kx1HQXi5WfZ2jIFakznGLwzl......"
IV: "AM+Ljm3np1XL+1SiM4IfM+pNx21zQ4q4XnK9DKoN3ZCWKV5CWt62z/myCEZt9e66g/wxC/Jeq1q6yTEaT0AIrwE8ek9OWGWCCFAOttmbYli+SCYzUf3yW0NrcQR3nerpbbXqGjQA4LnNbwm26vQ42AuWhRbK2V7MP0aN4E68NUMGVs+mOjaX6QbZ50wvILSTK0O/y/P2AYiHhXrWPlDajVy8kZ65m4qnPKbDnwzp5lK37fXs9jwwcUUUYW+9jQh4qVkOaQNKvUTZu5BqmDz8/A80B+Q9rt4hy3EdCphWM8bfJ7RE3/W8S/EVUcuElqpsvB6XkBy9Q+VbtjlotZcnnw=="
Key: "ngOW45g78VaMAAzbWPol9y99lTnjtNylAKstkZF2jWoXq3SQI5Vd+yS2/vNkdtat0BxI+UHKNL98IvvCf3JIYLAfpzFhRjBWCZwo2RZms4OJMwngItPGTFc9cHtSMbTNI5FlXMciJrrA+yj5HWZ3kcpVYn3d8tiXpGEVgEorxdxijhim9vsgXbXS5ZG39KwW2mxOMMiFdd/UbMZLC01zNpE5t8DmYNoMUmCva1Y6cDuZEt8DYM3z4rXLTd2EefnFuX/DcXiD9CKqMyw2bBmIFouv+qDVbnQ/bR5mjLGW/rC7TNELOU2Y/VFf+26wZe2u0C7MRsf9wAbcxPC6UAocAQ=="

代码

我遇到错误的行如下:

return String.fromCharCode.apply(null, new Uint8Array(decryptedData));

引发错误的整个方法如下:

//Method that will decrypt the data being received

  private async decryptData(data: any): Promise<any> {
    //Get the client private key from storage
    let clientPrivateKey = localStorage.getItem(AppSettings.PRIVATE_KEY);

    //Deserialize the JSON
    let response = data;

    //Get the buffer of the IV
    let ivBuffer = this.base64ToArrayBuffer(response.IV);

    //Get the private key in CryptoKey format
    let importedPrivateKey = await window.crypto.subtle.importKey(
      "pkcs8",
      this.base64ToArrayBuffer(clientPrivateKey),
      {
        name: "RSA-OAEP",
        hash: { name: "SHA-256" }
      },
      false,
      ["decrypt"]
    );
    //Get the bytes of the IV
    let ivBytes = await window.crypto.subtle.decrypt(
      {
        name: "RSA-OAEP",
      },
      importedPrivateKey,
      ivBuffer
    );

    //Take IV to text
    let ivArr = new Uint8Array(ivBytes);
    let IV = this.Utf8ArrayToStr(ivArr);

    //Get the buffer of the key
    let keyBuffer = this.base64ToArrayBuffer(response.Key);
    //Decrypt the key
    let keyBytes = await window.crypto.subtle.decrypt(
      {
        name: "RSA-OAEP"
      },
      importedPrivateKey,
      keyBuffer
    );
    //Take the key to text
    let keyArr = new Uint8Array(keyBytes);
    let key = await window.crypto.subtle.importKey(
      "raw", //can be "jwk" or "raw"
      keyArr,
      "AES-CBC",
      false, //whether the key is extractable (i.e. can be used in exportKey)
      ["encrypt", "decrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
    )

    //Take from B64 to bytes then decrypt
    let responseData = this.base64ToArrayBuffer(response.Data);
    //Decrypt the actual data
    //let decryptedData = await this.aes.decrypt(key, IV, responseData);
    let decryptedData = await window.crypto.subtle.decrypt(
      {
        name: "AES-CBC",
        iv: ivArr, //The initialization vector you used to encrypt
      },
      key, //from generateKey or importKey above
      responseData //ArrayBuffer of the data
    )

    //Return the decrypted data for use
    return String.fromCharCode.apply(null, new Uint8Array(decryptedData));
  }

Base64帮助器方法如下:

private arrayBufferToBase64(buffer) {
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
  }

  private base64ToArrayBuffer(b64) {
    var byteString = window.atob(b64);
    var byteArray = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
      byteArray[i] = byteString.charCodeAt(i);
    }

    return byteArray;
  }

1 个答案:

答案 0 :(得分:0)

我通过更改将ArrayBuffer解码为字符串的方式来解决了这个问题。

我替换了以下内容:

return String.fromCharCode.apply(null, new Uint8Array(decryptedData));

使用:

return new Uint8Array(decryptedData).reduce(function (data, byte) {
      return data + String.fromCharCode(byte);
    }, '');