I'm currently encrypting data in PHP as follows:
//$sMessage is the input to encrypt.
//$sPublicKey is the public key in PEM format.
openssl_public_encrypt($sMessage, $sEncrypted, $PublicKey, OPENSSL_PKCS1_OAEP_PADDING);
//$sEncrypted will now store the resulting text.
Here's an example of the code used to generate the key in PHP:
$aConfig = array(
"digest_alg" => "sha256",
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
$res = openssl_pkey_new($aConfig);
//$sPassPhrase is the pass phrase.
openssl_pkey_export($res, $sPrivateKey, $sPassPhrase);
//$sPrivateKey is the key (in PEM format).
And my decryption is using a private key that's protected by a pass phrase.
//$sPrivateKeyWithPassPhrase is the protected private key in PEM format.
//$sPassPhrase is the pass phrase to protect the key.
$newRes = openssl_pkey_get_private($sPrivateKeyWithPassPhrase, $sPassPhrase);
//$sEncrypted is the encrypted text (ciphertext).
openssl_private_decrypt($sEncrypted, $sDecrypted, $newRes, OPENSSL_PKCS1_OAEP_PADDING);
//$sDecrypted is the decrypted text (plaintext)
I've also found out how to decrypt with Python using the cryptography library (which you can learn about here):
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
#passphrase is the pass phrase
passphrase_bytes = bytes(passphrase, 'utf-8')
#privatekey is the encrypted private key
private_key = serialization.load_pem_private_key(
privatekey,
password=passphrase_bytes,
)
#ciphertext is the text to be decrypted
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA1()),
algorithm=hashes.SHA1(),
label=None
)
)
#plaintext will be the decrypted result.
However, I've been struggling to find a comparable function in JavaScript.
The best answer I found so far was this one: RSA Encryption Javascript
However, it doesn't seem like keys are in PEM format and when I go to the pidCrypt homepage to get more documentation, it's a 404 error.
I found this one as well: PHP's openssl_sign Equivalent in Node JS
The NodeJS library in general seems to have the right functions but when I went through the NodeJS documentation the Quick Start Guide seems to suggest that in order to use NodeJS I have to first install software and set up a web server. According to how to run node.js client on browser, it's not possible "Node.js is not browser javascript. There are many parts of it that use OS features not available in a browser context." (I'm hoping for something I can run in a native browser on the client-side.)
Someone suggested in a comment that I could use WebCrypto. After some struggle to figure out where to download it, I found it's actually native to the browsers (which was a pleasant surprise). However, I haven't been able to figure out how to import a PEM key from the documentation, and when I went to generate a key then export it, the only available formats were "jwk" (some sort of JavaScript object), "spki" (some kind of array buffer), and "pkcs8" (which I only got DOMException: key is not extractable). Nothing looks remotely like the OpenSSL PEM format. (I believe this is PKCS1.)
When I did "crypto.subtle.importKey" it wanted 5 different parameters (format, keyData, algorithm, extractable, keyUsages). None of those accept the PEM string. After a bit of struggle I did find SubtleCrypto importKey from PEM which confirmed that it's possible if you do fancy manipulation to import a PEM public key, however that's for public keys in PEM format and I have no idea how to handle pass phrases (and really I'd rather not program that all by hand). Then I found How can I import an RSA private key in PEM format for use with WebCrypto? and Javascript, crypto.subtle : how to import RSA private key? however those basically told me it's not possible unless I go and convert the private key to PKCS8 using a command line OpenSSL (that also has to be installed separately and I remember was a huge pain to get on Windows). And once I get past that hurdle, I'm still not sure how I would go about getting an equivalent pass phrase protection in PKCS8. I'm hoping there's something similar that ideally supports PKCS1 to do the same as the PHP and Python code above, and I can run it 100% in the native browser. (Importing more JavaScript code is okay.)
I'd ideally like to find a simple working JavaScript example for OpenSSL RSA decryption, equivalent to the PHP or Python ones above. If I have the private key PEM string, the pass phrase, and the cipher text it can give back the plaintext.
Thank you very much! I appreciate all your help a ton and you can save me many hours!