I have a ReactJS application that should be able to verify signatures with a given RSA public key like the Web Crypto API it does with subtle and import_key etc. Does any one knows if there exist such a library or how to use the Web Crypto API in react directly? I searched a lot, but I wasn't able to find a working example for me. Maybe I missed something.
I tried before the @trust/webcrypto library and installed it with npm.
This is the code that I tried before:
const crypto = require('@trust/webcrypto');
function base64decode(str) {
let buffer = Buffer.from(str, 'base64');
return new Uint8Array(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength));
}
function importRsaPublicKey(pem) {
const binaryDer = base64decode(pem);
return crypto.subtle.importKey(
"pkcs8",
binaryDer,
{
name: "RSA-PSS",
hash: "SHA-256",
},
true,
["verify"]
);
}
The RSA public key is given as a base64 string encoded in ASN.1 DER format.
As an example: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAimHHeNG9QnA7aMSjefJzMKfP...4XqwIDAQAB
My first problem is already to import it correctly. The signing is maybe already solved, when I have a working library.
When I try the code above I get the following error in my ReactJS application: Unhandled Rejection (Error): Cannot find module '../algorithms/RSA-PSS'
I searched for the problem and it seems that I am not able to use it in react that is why I asked if someone knows a library which is working in react to import a RSA public key and is able to verify a signed message with a given signature.
The second library that I tried was @peculiar/webcrypto
, but that seems also not to work.
The code that I tried:
const { Crypto } = require("@peculiar/webcrypto");
const crypto = new Crypto();
function importRsaPublicKey(pem) {
const binaryDer = base64decode(pem);
return crypto.subtle.importKey(
"pkcs8",
binaryDer,
{
name: "RSA-PSS",
hash: "SHA-256",
},
true,
["verify"]
);
}
This raises the error of: Unhandled Rejection (Error): Data does not match to PrivateKeyInfo ASN1 schema.
The public key is definitely in ASN.1 DER encoding, but it is a public key and not a private key. I don't need the private key in my setting.
@Topaco mentioned to use a public key I has to use the spki
format. That solves the issue with the import of the public key.
This code solves my problem.
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function importRsaPublicKey(pem) {
const binaryDerString = atob(pem);
const binaryDer = str2ab(binaryDerString);
return crypto.subtle.importKey(
"spki",
binaryDer,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
},
true,
["verify"]
);
}
I used the RSASSA-PKCS1-v1_5
algorithm as it doesn't require a salt.