I am trying to use the SubtleCrypto Web API in Ionic to encrypt data using a public key. I am importing the key in PEM format and then passing it onto window.crypto.subtle.importKey
and then using that result into window.crypto.subtle.encrypt
It would appear that there is a problem with the window.crypto.subtle.importKey
- I am getting a Uncaught (in promise): DataError
when I am trying to import the key.
I am currently using the following methods to import the key:
//Get the public key in CryptoKey format
let importedPublicKey = await window.crypto.subtle.importKey(
"pkcs8",
this.pemPublicToArrayBuffer(serverPublicKey),
{
name: "RSA-OAEP",
hash: {name: "SHA-256"}
},
true,
[]
);
private pemPublicToArrayBuffer(pem) {
var b64Lines = this.removeLines(pem);
var b64Prefix = b64Lines.replace('-----BEGIN PUBLIC KEY-----', '');
var b64Final = b64Prefix.replace('-----END PUBLIC KEY-----', '');
return this.base64ToArrayBuffer(b64Final);
}
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;
}
Does anyone possibly know why the key import is failing with the PEM public key?
I've spent quite some time struggling with this error myself, and now I'm sure I can give you (and anyone else) some good advice on this.
You are passing "pkcs8" as a format to the importKey method, but if you are importing a PUBLIC key, the format is likely to be the "spki" (SubjectPublicKeyInfo) a special format for public keys, while "pkcs8" supposed to be used for PRIVATE keys. That brings us to the next point:
Where did you get this key from? If you are exporting public key with the OpenSSL cli (openssl rsa -pubout -in priv.pem -out pub.pem) then you are getting the key in "spki" format (default one).
You should pass ["encrypt"] as a "usages" parameter to the importKey (instead of an empty array) if you are importing a PUBLIC key, otherwise you will end up with one of the following errors: "SyntaxError: Cannot create a key using the specified key usages" (wrong usage specified for the key) or "InvalidAccessError: key.usages does not permit this operation" (empty array of usages). Things to keep in mind here is that Public keys can be used only to ["encrypt"] and Private keys to ["decrypt"]. I haven't tried to import key pairs though, but as I understand it, you should pass "pkcs8" as a format, and ["encrypt", "decrypt"] for usages.
Even if you set up all the above properly, you may still get the nasty "Uncaught (in promise): DataError", for me it was due to the format mismatch, I've been passing a key in PKCS#1 RSAPublicKey format with the "spki" parameter. So you should probably start from inspecting your key to get exact format and algorithm details from it.
Hope this helps someone. Ivan