I want to use the same public-private key to do some encryption/decryption at the code level and want to send encrypted data to the backend along with my public key which I am appending inside of my JWT AUTH Token. So pls help me to encrypt / decrypt with that approach if possible, as I can't change this code due to reusability
const keyDetails = await window.crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: 'SHA-256' },
},
true,
['verify', 'sign']
);
I tried that way but got an error.
Also, I want to use my exported public and private keys which I am doing with that approach
const publicKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
const enc = new TextEncoder();
const encodedText = enc.encode("testing 1234");
const encryptedText = await window.crypto.subtle.encrypt({
name: "RSASSA-PKCS1-v1_5"
},
publicKey,
encodedText
)
console.log(encryptedText);
const decryptedText = await window.crypto.subtle.decrypt({
name: "RSASSA-PKCS1-v1_5"
},
privateKey,
encryptedText
)
TypeError: Failed to execute 'encrypt' on 'SubtleCrypto': parameter 2 is not of type 'CryptoKey'.
RSASSA-PKCS1-v1_5 is a padding that is applied during signing/verification. It cannot be used for encryption/decryption. The padding for encryption/decryption is RSAES-PKCS1-v1_5, but this is not supported by WebCrypto API. WebCrypto only supports RSAES-OAEP for encryption/decryption. See RFC8017 and WebCrypto API for more details.
Also, the exported JWK keys must first be adapted for encryption/decryption. Then the keys must be imported before they can be used in encryption/decryption.
The following example demonstrates this: First, a key pair for signing/verifying with RSASSA-PKCS1-v1_5 is generated. Both keys are exported as JWK. Then the key_ops
and alg
parameters are adjusted. Afterwards, the modified keys are re-imported and used for encryption/decryption with RSAES-OAEP:
(async () => {
// Generate
const keyDetails = await window.crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: 'SHA-256' },
},
true,
['verify', 'sign']
);
console.log(keyDetails)
// Export
const publicKey = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
console.log(publicKey)
console.log(privateKey)
// Adapt parameters and import
publicKey.key_ops = ['encrypt'];
privateKey.key_ops = ['decrypt'];
publicKey.alg = 'RSA-OAEP-256';
privateKey.alg = 'RSA-OAEP-256';
const publicKeyReloaded = await window.crypto.subtle.importKey("jwk", publicKey, {name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["encrypt"]);
const privateKeyReloaded = await window.crypto.subtle.importKey("jwk", privateKey,{name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["decrypt"]);
console.log(publicKeyReloaded)
console.log(privateKeyReloaded)
// Encrypt/Decrypt
const enc = new TextEncoder();
const encodedText = enc.encode("testing 1234");
const encryptedText = await window.crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKeyReloaded, encodedText)
console.log(ab2b64(encryptedText));
const dec = new TextDecoder();
const decryptedText = await window.crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKeyReloaded, encryptedText)
console.log(dec.decode(decryptedText));
// Helper
function ab2b64(arrayBuffer) {
return window.btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}
})();
Note that in general the same key pair should actually be used for either signing/verifying or encrypting/decrypting, not for both together, see here.
WebCrypto API provides some protection against this misuse by binding the purpose of the key to it (however, this protection can be circumvented all too easily, as shown above).