user12360954
user12360954

Reputation:

TypeError: Key is not of type 'CryptoKey'

I'm using Node with @peculiar/webcrypto library to encrypt the string that I input; however, it produce this TypeError, but the same code working fine inside Chrome Browser. I'm very new to Node and Async.

Here is the code :

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

Upvotes: 1

Views: 6058

Answers (1)

Matt Oestreich
Matt Oestreich

Reputation: 8528

The reason this was happening is because by the time crypt() was running, iKey() had not finished..

The fix was to move e_key = iKey() into the crypt() function, and make the crypt() function an async function, so that we can await for iKey() to finish before trying to use the data it returns..

crypt now looks like:

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

This is the full file:

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

Which returns:

// 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
]


Update:

The reason you can't use it in the global scope is because of how Node handles async operations. With that being said, you have a couple of options:

Option 1

Instead of using await for iKey() (which is just syntactic sugar for Promises) you could use .then with it, as well as turn crypto into a Promise based function:

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

Option 2:

Wrap everything in an async immediately invoked function expression..

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

There are also Promise libraries, like BlueBird, you can use to make this easier, but that's pretty much the gist of it..


Update 2:

This is how you can use a 'global function' with a promise.

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

Upvotes: 1

Related Questions