I need to encrypt data on browser side and decrypt it in Rails application using RSA.
Currently I'm using JSEncrypt
library on JS side but I want to replace it with builtin Web Crypto API.
I need to use existing RSA public key for encryption, which was generated by ruby OpenSSL
standard library for backward compatibility with that already encrypted and saved.
I've managed to import RSA pubkey to JS as JWK or SPKI and encrypt data, but Ruby side failed to decrypt it.
JWK import and encryption:
let pubKey = await crypto.subtle.importKey(
"jwk",
{
kid: "1",
kty: "RSA",
use: "enc",
key_ops: ["encrypt"],
alg: "RSA-OAEP-256",
e: pubKeyE,
n: pubKeyN
},
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: "SHA-256" }
},
false,
["encrypt"]
);
console.log("pubKey imported");
let encryptedBuf = await crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
pubKey,
stringToArrayBuffer(content)
);
let encrypted = arrayBufferToString(encryptedBuf);
SPKI import and encryption:
let pubKey = await crypto.subtle.importKey(
"spki",
stringToArrayBuffer(atob(pubKeyBase64)),
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: "SHA-256" }
},
false,
["encrypt"]
);
console.log("pubKey imported");
let encryptedBuf = await crypto.subtle.encrypt(
{
name: "RSA-OAEP"
},
pubKey,
stringToArrayBuffer(content)
);
let encrypted = arrayBufferToString(encryptedBuf);
Ruby public key generation and decryption:
rsa = OpenSSL::PKey::RSA.new(pem_private_key)
js_encrypted = Base64.decode64(js_encrypted_base64)
js_decrypted = rsa.private_decrypt(js_encrypted, OpenSSL::PKey::RSA::NO_PADDING)
see complete reproducable examples here:
https://repl.it/@senid231/Web-Crypto-API-encrypt-with-imported-rsa-pubkey-as-JWK#script.js
https://repl.it/@senid231/Web-Crypto-API-encrypt-with-imported-rsa-pubkey-as-SPKI#script.js
https://repl.it/@senid231/Ruby-RSA-decrypt-data-encrypted-by-JS#main.rb
Thanks to Topaco comment, I've managed find out how to decrypt message on ruby side.
ruby OpenSSL standard library does not implement modern
RSA-OAEP
, but there is a gem, that do can add this functionality.Message was encrypted by WEb Crypto API with public key imported in SPKI format.
https://github.com/terashi58/openssl-oaep