简体   繁体   中英

How to export Web Crypto key to jsrsasign

I try to generate a RSA key with Web Crypto and use it to sign a string with jsrsasign ( Firefox does not support RSA-PSS ). Therefore, I export the Web Crypto key and convert it to PKCS8-PEM, but when I call KEYUTIL.getKeyFromPlainPrivatePKCS8PEM to import the key to jsrsasign an error is thrown: malformed plain PKCS8 private key(code:001)

What did I wrong? JSBin

window.crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    hash: {name: "SHA-256"},
  },
  true,
  ["encrypt", "decrypt"]
)
.then(keyPair => window.crypto.subtle.exportKey("pkcs8", keyPair.privateKey))
.then(arrayBufferToBase64String)
.then(toPem)
.then(pem => {
  var rsa = KEYUTIL.getKeyFromPlainPrivatePKCS8PEM(pem); // throws: malformed plain PKCS8 private key(code:001)
  var sig = rsa.signStringPSS('text', 'sha256', 32);
  console.log('signature', sig);
})
.catch(::console.error)

function arrayBufferToString(arrayBuffer) {
  var byteArray = new Uint8Array(arrayBuffer)
  var byteString = '';
  for (var i=0; i<byteArray.byteLength; i++) {
    byteString += String.fromCharCode(byteArray[i]);
  }
  return byteString;
}

function arrayBufferToBase64String(arrayBuffer) {
  return btoa(arrayBufferToString(arrayBuffer));
}

function toPem(key) {
  return `
-----BEGIN RSA PRIVATE KEY-----
${key}
-----END RSA PRIVATE KEY-----
`;
}

Edit:

I just realized that jsrsasign can handle jwk :

window.crypto.subtle.generateKey(
  {
    name: "RSA-OAEP",
    modulusLength: 2048,
    publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
    hash: {name: "SHA-256"},
  },
  true,
  ["encrypt", "decrypt"]
)
.then(keyPair => window.crypto.subtle.exportKey("jwk", keyPair.privateKey))
.then(jwk => {
  var rsa = KEYUTIL.getKey(jwk);
  var sig = rsa.signStringPSS('text', 'sha256', 32);
  console.log('signature', sig);
})
.catch(::console.error)

I prefer this solution, but I still like to know why my pkcs8 solution does not work.

It doesn't work by changing PEM header from "----BEGIN RSA PRIVATE KEY-----" to "-----BEGIN PRIVATE KEY-----" since the content is different. I think using JWK for file exporting is the best way to do this since it will have much interoperability among any browser. I've tried the same thing before however PKCS#8 doesn't work on some browsers.

As Felix described, your RSA key is a PKCS#1 key which has "-----BEGIN RSA PRIVATE KEY-----" PEM header.

If you need to convert PKCS#1 to PKCS#8 key KEYUTIL class may be useful like in this example:

keyobj = KEYUTIL.getKey("-----BEGIN RSA PRIVATE KEY-----..."); // your key
pkcs8pem = KEYUTIL.getPEM(keyobj, "PKCS8PRV");

Your PEM encoded key is actually PKCS#1 and not PKCS#8 due to the 'RSA' part. This is just the RSA key object in DER without the key identifier wrapped in a sequence.

jsrsasign is looking for a PKCS#8 header "BEGIN PRIVATE KEY" and not "BEGIN RSA PRIVATE KEY". Changing the header makes it work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM