1

I'm developing a website using this JS plugin to encrypt some data and send it to the server: https://github.com/travist/jsencrypt

I'm running Python 3 with Django, the problem is I can't decrypt the data on the server. My code is:

JS Code:

pkey = "-----BEGIN PUBLIC KEY-----\
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDeVs9mcWUtTgi93/KXMNA/IF7S\
oQcZAmKQueygoDp9XUM3xnxPb/6XNpJQII85Hxbljqs/xuPVtxo5ovyJ+XXIPV8+\
eG6kSDmr2C3NpBUtfoUeADC/1H1jy44T6stBgXGMwTPokhjvSyEbGpkgMGo74Rpq\
q1vHofh3KcPNoaYH4wIDAQAB\
-----END PUBLIC KEY-----";


var encrypter = new JSEncrypt;
encrypter.setPublicKey(pkey);
encrypter.encrypt('Testing...');

And I get:

"STg7Fnm6Y6cAgMXEt4SxP8rbMb/pFB2X9Y1z8pAOoCNO9y8XuhVmQuG/FRBSqM+3ge43x9kfYMideAUu69RothwEOYmNnVrfwqm7SLm3voEcSXCqst2S7prTmCvYW43WyAAUl0vNxV+7xsm/yciQ4XV+jZSKd3xidbWL1BTTUw8="

Python Code:

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from base64 import *


def decrypt(key, text):
    if type(key) == str:
        key = key.encode()
    if type(text) == str:
        text = text.encode()

    rsakey = RSA.importKey(key)
    rsakey = PKCS1_OAEP.new(rsakey)
    d = rsakey.decrypt(text)
    return d

text = "STg7Fnm6Y6cAgMXEt4SxP8rbMb/pFB2X9Y1z8pAOoCNO9y8XuhVmQuG/FRBSqM+3ge43x9kfYMideAUu69RothwEOYmNnVrfwqm7SLm3voEcSXCqst2S7prTmCvYW43WyAAUl0vNxV+7xsm/yciQ4XV+jZSKd3xidbWL1BTTUw8="

text = b64decode(text.encode())

with open('private.pem', 'rb') as f:
    key = f.read()
decrypt(key, text)

And I get:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.2/dist-packages/Crypto/Cipher/PKCS1_OAEP.py", line 227, in decrypt
    raise ValueError("Incorrect decryption.")
ValueError: Incorrect decryption.

The private key I'm using in this example is:

-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCO9YbJ8Z+tW0ucnMdXGNzmcvWaaLRGsx5iUHslbZ1tjec63HDm
6Hr2hv56u5zytyF4Cd/0lBNRC9qf/1XlEFqeSRifsyHZpPfyZn0fbHWYLH8g5FE4
VqrMe79ubSVx2eGWwwaLvEO+yaO1AF/fxWT6Ir8AUikMFFAnX+fBaA3XIwIDAQAB
AoGADxuniQP+CgYR8ZUoA+5eugQALLdQBgC7/0veF9CDyKYsf634SI7dH9yYXEQj
jAsKgHMatfBIMlJ8YlhLrY+S4+r26goNEqygtqetJ6NuePKQQ8xEERP4icsaBpY7
WqeU6AZOMlyq8o+e4DMnuxGpf8UT+lLx1G9AmVJf3+6NONECQQDLX94BmW//48Y6
yg9wnO6TR1msrGd1PFRqyJ9eilj8chI2JxiHkhepiTlBU7eyjUv4aeE7U84mp3Zo
AtPoiKmlAkEAs/OQM9IDttfgdS/yK6vZr1myNAbKOdv1rVId7MAspGHbN//gzb4s
r4mZKsIAi+jaDhpMvYbUxJe9y5HAY3XTJwJAe3hcZEQvRv+WHaMG9KuR/EBZJQgW
V4qlBZ9/gfokRD9M5yudLNF5JCh3Zj3ZTMGT2eEOKOKcScNpk4QD+yzdMQJAQlSM
Gd3WyqXmMav7qwdMVStN2YmLLyqZ80oqh6MKkYkUgh7KYWwxEn84ux8JjojFH5+o
G9BASzrXldrivIaozwJAVAHr9ON/altcDyh/OjkJff/3xXzHB3Zxvy4WykkO/PdF
tOqpAnYso3mCsEQsCcrJCflkFmJuYsvu4+Tm4GiqVg==
-----END RSA PRIVATE KEY-----

If I try to decrypt it on JS it works as intended:

private = "-----BEGIN RSA PRIVATE KEY-----\
MIICWwIBAAKBgQCO9YbJ8Z+tW0ucnMdXGNzmcvWaaLRGsx5iUHslbZ1tjec63HDm\
6Hr2hv56u5zytyF4Cd/0lBNRC9qf/1XlEFqeSRifsyHZpPfyZn0fbHWYLH8g5FE4\
VqrMe79ubSVx2eGWwwaLvEO+yaO1AF/fxWT6Ir8AUikMFFAnX+fBaA3XIwIDAQAB\
AoGADxuniQP+CgYR8ZUoA+5eugQALLdQBgC7/0veF9CDyKYsf634SI7dH9yYXEQj\
jAsKgHMatfBIMlJ8YlhLrY+S4+r26goNEqygtqetJ6NuePKQQ8xEERP4icsaBpY7\
WqeU6AZOMlyq8o+e4DMnuxGpf8UT+lLx1G9AmVJf3+6NONECQQDLX94BmW//48Y6\
yg9wnO6TR1msrGd1PFRqyJ9eilj8chI2JxiHkhepiTlBU7eyjUv4aeE7U84mp3Zo\
AtPoiKmlAkEAs/OQM9IDttfgdS/yK6vZr1myNAbKOdv1rVId7MAspGHbN//gzb4s\
r4mZKsIAi+jaDhpMvYbUxJe9y5HAY3XTJwJAe3hcZEQvRv+WHaMG9KuR/EBZJQgW\
V4qlBZ9/gfokRD9M5yudLNF5JCh3Zj3ZTMGT2eEOKOKcScNpk4QD+yzdMQJAQlSM\
Gd3WyqXmMav7qwdMVStN2YmLLyqZ80oqh6MKkYkUgh7KYWwxEn84ux8JjojFH5+o\
G9BASzrXldrivIaozwJAVAHr9ON/altcDyh/OjkJff/3xXzHB3Zxvy4WykkO/PdF\
tOqpAnYso3mCsEQsCcrJCflkFmJuYsvu4+Tm4GiqVg==\
-----END RSA PRIVATE KEY-----\
"
text = "STg7Fnm6Y6cAgMXEt4SxP8rbMb/pFB2X9Y1z8pAOoCNO9y8XuhVmQuG/FRBSqM+3ge43x9kfYMideAUu69RothwEOYmNnVrfwqm7SLm3voEcSXCqst2S7prTmCvYW43WyAAUl0vNxV+7xsm/yciQ4XV+jZSKd3xidbWL1BTTUw8="

encrypter.setPrivateKey(private);
encrypter.decrypt(text);

And I get:

"Testing"

But I just can't make it work on Python.

What am I doing wrong?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Enuff
  • 457
  • 5
  • 21

3 Answers3

3

jsencrypt depends on the jsbn library which doesn't provide OAEP, but only PKCS#1 v1.5 padding.

You have to use the same in python which PyCrypto provides. Simply use PKCS1_v1_5 instead of PKCS1_OAEP.


Note that PKCS#1 v1.5 padding shouldn't be used today anymore. I suggest you use the forge library which provides an RSA implementation with OAEP.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
0

Using PKCS1_v1_5:

def decrypt(key, text):
    if type(key) == str:
        key = key.encode()
    if type(text) == str:
        text = text.encode()

    rsakey = RSA.importKey(key)
    rsakey = PKCS1_v1_5.new(rsakey)
    d = rsakey.decrypt(text, 'bollox')
    return d

>>> decrypt(key, text)
b'Testing'
AChampion
  • 29,683
  • 4
  • 59
  • 75
  • what is the sentinel 'bollox'? – 66lotte Oct 20 '21 at 15:56
  • 1
    You want to know the meaning of "bollox" (bollocks) or what the purpose of the sentinel is? The sentinel is returned when the decryption fails, can be any object. This just returns the string "bollox" on decryption failure. It's [an english slang term](https://en.wikipedia.org/wiki/Bollocks#:~:text=stark%20bollock%20naked%22.-,Bollocks%20(singular%20noun),and%20have%20a%20pint!%22.) that has a lot of uses but here it expresses that something went wrong. – AChampion Oct 20 '21 at 19:04
  • I was wondering because I dont get the critery of 'bollox' used here and `Crypto.Random.new()` in some other examples! Both have led to the same result. – 66lotte Oct 20 '21 at 19:34
0

I had been using JSEncrypt JavaScript file to achieve conversation between JavaScript and Python using pycrypto however during encryption in JavaScript it uses a random pad in the function pkcs1pad2 which needed to be removed and it started working. It had been a hack but it worked out. Following are the lines are commented out from function pkcs1pad2(s,n)

while(n > 2) { // random non-zero pad
    x[0] = 0;
    while(x[0] == 0) rng.nextBytes(x);
    ba[--n] = x[0];
  }

  ba[--n] = 2;
  ba[--n] = 0;
Tejas Sherdiwala
  • 750
  • 8
  • 15