首页 > 解决方案 > TypeError:密钥不是“CryptoKey”类型

问题描述

我正在使用带有 @peculiar/webcrypto 库的 Node 来加密我输入的字符串;但是,它会产生此 TypeError,但相同的代码在 Chrome 浏览器中运行良好。我对 Node 和 Async 很陌生。

这是代码:

const { Crypto } = require("@peculiar/webcrypto");
const crypto = new Crypto();
const btoa = require('btoa');

const CC = "Hello World";
const b_size = CC.length;
P = new ArrayBuffer(b_size);
C = new Uint8Array(P);

function iKey() {
  return crypto.subtle.importKey(
    "jwk",{
      kty:"RSA",
      e:"AQAB",
      n:"gfJ-DTivOto0B1qvI9jGQgLvPvEkfVzbhf4-GM_XGrSyJRa1ASOZV89qpBIYDq8lwSwxibybvRqROhNavH6X_xQux9TAhDVBYZv8bH7pR4cfCLQrNvbpFRan3XBv7zeifGThyJGJ8R0BJTh4R4K9cu7kE48Ig1GO6iIx6emnYaQBhRUHsLfxfhQCwlHLraOXcP_RPM9TfZRO4dVHdRrdX1B60B6OqwU1ojRmo1oLiJCN6KjwMsYbSbYnflt_uyFUGxxBQE-1qnhBkarm10pgIgVDiSIn8XKQBxLg-Ao6cc7pXytp7Bd--g45OKHinRKaSP-Ub8g3S9g4LV2Qt8UZbQ",
      alg:"RSA-OAEP-256",
      ext:true
    },
    {
      name:"RSA-OAEP",
      hash: {name: "SHA-256"}
    },
    true,
    ["encrypt"]
  );
}

e_key = iKey();

for(i=0; i < b_size; ++i) {
  C[i] = CC.charCodeAt(i);
}


function crypt() {
  return crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
      hash: {name: "SHA-256"}
    },
    e_key, P
  ).then(function(encrypted){
    console.log(new Uint8Array(encrypted));
  }).catch(function(err){
    console.error(err);
  });
}

crypt();

标签: node.jsencryptioncryptographywebcrypto-api

解决方案


发生这种情况的原因是因为时间crypt()正在运行,iKey()还没有完成..

解决方法是移入e_key = iKey()函数crypt()并使crypt()函数成为异步函数,这样我们就可以awaitiKey()尝试使用它返回的数据之前完成..

地穴现在看起来像:

async function crypt() {
  let e_key = await iKey();

  return crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
      hash: {name: "SHA-256"}
    },
    e_key, P
  ).then(function(encrypted){
    console.log(new Uint8Array(encrypted));
  }).catch(function(err){
    console.error(err);
  });
}

这是完整的文件:

const { Crypto } = require("@peculiar/webcrypto");
const crypto = new Crypto();
const btoa = require('btoa');

const CC = "Hello World";
const b_size = CC.length;
P = new ArrayBuffer(b_size);
C = new Uint8Array(P);

function iKey() {
  return crypto.subtle.importKey(
    "jwk",{
      kty:"RSA",
      e:"AQAB",
      n:"gfJ-DTivOto0B1qvI9jGQgLvPvEkfVzbhf4-GM_XGrSyJRa1ASOZV89qpBIYDq8lwSwxibybvRqROhNavH6X_xQux9TAhDVBYZv8bH7pR4cfCLQrNvbpFRan3XBv7zeifGThyJGJ8R0BJTh4R4K9cu7kE48Ig1GO6iIx6emnYaQBhRUHsLfxfhQCwlHLraOXcP_RPM9TfZRO4dVHdRrdX1B60B6OqwU1ojRmo1oLiJCN6KjwMsYbSbYnflt_uyFUGxxBQE-1qnhBkarm10pgIgVDiSIn8XKQBxLg-Ao6cc7pXytp7Bd--g45OKHinRKaSP-Ub8g3S9g4LV2Qt8UZbQ",
      alg:"RSA-OAEP-256",
      ext:true
    },
    {
      name:"RSA-OAEP",
      hash: {name: "SHA-256"}
    },
    true,
    ["encrypt"]
  );
}

/** COMMENTED THIS LINE OUT */
// e_key = iKey();

for(i=0; i < b_size; ++i) {
  C[i] = CC.charCodeAt(i);
}

async function crypt() {
  /** MOVED iKey INTO HERE */
  let e_key = await iKey();

  return crypto.subtle.encrypt(
    {
      name: "RSA-OAEP",
      hash: {name: "SHA-256"}
    },
    e_key, P
  ).then(function(encrypted){
    console.log(new Uint8Array(encrypted));
  }).catch(function(err){
    console.error(err);
  });
}

crypt();

返回:

// return
Uint8Array(256) [
   17,  88,  41, 189, 185, 200, 225,  96, 186, 155, 153, 212,
  207,  91, 203,   5,  38, 152,  19, 107, 182, 180, 210,  54,
  236, 153, 204, 112, 148,  65, 246, 208,  34,  90, 251,  40,
   64,  33, 175, 123,  84,  59, 249,  24, 125, 219,  65, 220,
    7, 186, 175, 204, 123,  41, 121, 143, 163, 100, 223, 180,
  167,  99,  19,  52, 117, 145, 215, 188, 226, 173, 237, 244,
  165, 101, 203, 104,  60,  26, 255, 181,  80, 185, 240, 162,
  156, 215, 212,  39,  13, 215,  51, 192, 167, 183,   4, 160,
  206,  92,  97,  84,
  ... 156 more items
]


更新:

您不能在全局范围内使用它的原因是 Node 处理异步操作的方式。话虽如此,您有几个选择:

选项1

除了使用awaitfor iKey()(它只是 Promises 的语法糖),你可以使用.then它,也可以crypto变成一个Promise基于函数:

// code above removed for brevity

function crypt(key) {
  return new Promise((resolve, reject) => {
    crypto.subtle.encrypt(
      {
        name: "RSA-OAEP",
        hash: {name: "SHA-256"}
      },
      key, P
    ).then(encrypted => {
      resolve(new Uint8Array(encrypted));
    }).catch(err => {
      reject(err);
    });
  })
}

// Use it like:
iKey().then(e_key => {
  crypt(e_key) // <- we are now passing the key in as a param
    .then(enc => console.log(enc))
    .catch(err => console.error(err))
}).catch(error => {
  console.error(error);
})

选项 2:

将所有内容包装在异步立即调用的函数表达式中。

(async () => {
  const e_key = await iKey();

  // also async now
  async function crypt() {
    return crypto.subtle.encrypt(
      {
        name: "RSA-OAEP",
        hash: {name: "SHA-256"}
      },
      e_key, P
    ).then(encrypted => {
      return new Uint8Array(encrypted);
    }).catch(err => {
      throw err;
    });
  }

  try {
    const enc = await crypt();
    console.log(enc);
  } catch (err) {
    console.error(err);
  }
})();

还有一些 Promise 库,比如 BlueBird,您可以使用它来简化此操作,但这就是它的要点。


更新 2:

这就是您如何使用带有承诺的“全局函数”。

const {
  Crypto
} = require("@peculiar/webcrypto");
const crypto = new Crypto();
const btoa = require('btoa');

const CC = "Hello World";
const b_size = CC.length;
P = new ArrayBuffer(b_size);
C = new Uint8Array(P);

function iKey() {
  return crypto.subtle.importKey(
    "jwk", {
      kty: "RSA",
      e: "AQAB",
      n: "gfJ-DTivOto0B1qvI9jGQgLvPvEkfVzbhf4-GM_XGrSyJRa1ASOZV89qpBIYDq8lwSwxibybvRqROhNavH6X_xQux9TAhDVBYZv8bH7pR4cfCLQrNvbpFRan3XBv7zeifGThyJGJ8R0BJTh4R4K9cu7kE48Ig1GO6iIx6emnYaQBhRUHsLfxfhQCwlHLraOXcP_RPM9TfZRO4dVHdRrdX1B60B6OqwU1ojRmo1oLiJCN6KjwMsYbSbYnflt_uyFUGxxBQE-1qnhBkarm10pgIgVDiSIn8XKQBxLg-Ao6cc7pXytp7Bd--g45OKHinRKaSP-Ub8g3S9g4LV2Qt8UZbQ",
      alg: "RSA-OAEP-256",
      ext: true
    }, {
      name: "RSA-OAEP",
      hash: {
        name: "SHA-256"
      }
    },
    true,
    ["encrypt"]
  );
}

/** COMMENTED THIS LINE OUT */
// e_key = iKey();

for (i = 0; i < b_size; ++i) {
  C[i] = CC.charCodeAt(i);
}

function crypt(key) { // <-- Notice we now pass in the key via a param
  return new Promise((resolve, reject) => {
    crypto.subtle.encrypt({
        name: "RSA-OAEP",
        hash: {
          name: "SHA-256"
        }
      },
      key, P
    ).then(function (encrypted) {
      resolve(new Uint8Array(encrypted));
    }).catch(function (err) {
      reject(err);
    });
  })
}

function someGlobalFunction(encryptedValue) {
  console.log("\r\n\r\nFROM GLOBAL FUNCTION:\r\n\r\n");
  console.log(encryptedValue);
  console.log("This is some global function");
  console.log("I am taking the encryped value as a param and doing something with it");
  console.log("For now, I just logged it to console..(see above)");
}

iKey().then(e_key => {
  crypt(e_key).then(encryped => { // <-- Notice we now pass in the key via a param
    someGlobalFunction(encryped);
  }).catch(error => {
    console.error(error);
  })
}).catch(err => {
  console.error(err);
});

推荐阅读