Reputation: 320
I would like to encrypt my password using Public Key in RSA format with PKCS1-1.5 padding. Currently I try to use forge
library from https://github.com/digitalbazaar/forge. Part of the solution uses Tom Wu's BigInteger()
.
modulus = new forge.jsbn.BigInteger(modulus,16);
exponent = new forge.jsbn.BigInteger(exponent, 16);
var text = "Password";
var rsa = forge.pki.rsa;
var publicKey = rsa.setPublicKey(modulus, exponent);
var encryptedData = publicKey.encrypt(text, 'RSAES-PKCS1-V1_5');
provided exponent - 10001 seems to be parsed properly in BigInteger()
as it returns single item array - 65537.
However when I push modulus 9bedc7ad20bdacf930f1471d0c2a9f7f1895e24d73957b145b621e7800589ec14a3122df556fae94cc45df7b1f5003062df5681a18d8165377a6dece1a8c36e0af6ce13e89890b6813eb94135bd8c4b2b743ef6d24cfc09cbd59a8105c3f31d56a0224b1db14c2e6396493571ef83d664c5b6169a1b42f988cfc3f7d39d50aa9
I get something strange as BigInteger()
results:
modulus screenshot
Therefore RSA keypair created later in the code is wrong. Could anyone point me to the right direction? What is even more frustrating is that I have working .py script and cannot convert it to JS.. I cannot use any server side programming here. (I am aware of the issues / risks with JS password encryption btw).
Update
Here's the working python Script:
import binascii
import Crypto
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from base64 import b64decode
def assymmetric_encrypt(val, public_key):
modulusDecoded = long(public_key["n"], 16)
exponentDecoded = long(public_key["e"], 16)
keyPub = RSA.construct((modulusDecoded, exponentDecoded))
print(keyPub)
# Generate a cypher using the PKCS1.5 standard
cipher = PKCS1_v1_5.new(keyPub)
return cipher.encrypt(val)
# Encrypt the password used to login
encryptedPassword = assymmetric_encrypt(password_input,public_key)
It looks that JS should be doing the same but when providing the same modulus exponent in both scripts, the encrypted password is different (looks similar but is not equal)
Update: Funny thing is that if I run JS script with hardcoded n, e and password I get the same encrypted data every time. When I do the same with Python script I alway get different result.. So there might be something more in the Crypto library..
Update 2: problem was located in completely different place. Thanks to Maarten Bodewes comment, it turned out that padding library was broken (didn't generate new string each time). I changed forger lib to JSencrypt for this part and it works great. Going through pem file but this will be probably altered in the future for better performance:
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pem);
var encrypted_jeencrypt= encrypt.encrypt(password);
var encrypted_jeencrypt_hex = base64toHEX(encrypted_jeencrypt);
Upvotes: 1
Views: 6881
Reputation: 39241
I believe the way you are building the modulus is correct. The problem is probably due you are using a string to encrypt and forge needs a buffer. Try this:
var buf = forge.util.createBuffer(text, 'utf8');
var encryptedData = publicKey.encrypt(buf, 'RSAES-PKCS1-V1_5');
If you are going to use RSA encryption to send passwords, I suggest you to use the more secure RSA-OAEP
via a SSL/TLS channel. RSA_PKCS1-V1_5
and RSA-OAEP
are non-deterministic and generate a different ciphertext each time. The correct way to compare if a message is correct is decrypting it
Upvotes: 1