0

I am trying to make my python function work the same as my js function and I can not figure out the difference between these two pieces of code. I have a feeling something is different with python's int() and node's forge.jsbn.BigInteger. Could anyone spot the difference between these two code samples?

Python (not working)

import base64
import hashlib

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

def returnSignature():
    password = "6b0d"
    salt = "1234"
    mod = "18482445774037006176143036388197818377224243341874299759393986316969168081293431967665057665354002144386679806241726680717167432197115393709044305367801562368377199313542622242088334493968227031303600659164182705200363370843349892071172286671217348220799611979367426886573857836700695154474387375045676161964264719840020610569587332497543980147743876907161648026576356758480646523434992364261325929823041766729482733300160147897964050534385377467240755626731087578114754411412866113305365456719741211653254865891742861999731525476635260033457850071277557432915055294927970289560714643822194080384022366782758886009197"
    exp = "65537"

    sha_1 = hashlib.sha1()
    sha_1.update(password.encode())

    password_sha1 = sha_1.hexdigest()
    salted_password = password_sha1 + salt
    SHA3_512_password_salted = hashlib.sha3_512(bytes.fromhex(salted_password)).digest()

    n = int(mod, 10)
    e = int(exp, 10)

    RSA_key = RSA.construct((n, e))
    publicKey = RSA_key.public_key()

    encryptor = PKCS1_OAEP.new(publicKey)
    encrypted = encryptor.encrypt(SHA3_512_password_salted)

    final = encrypted.hex()
    
    return final

if __name__ == "__main__":
    print(returnSignature())

Javascript (working)

var CryptoJS = require("crypto-js");
var jsSHA = require("jssha");
var forge = require("node-forge");

var returnSignature = () => {
    var password = "6b0d";
    var salt = "1234";
    var mod = "18482445774037006176143036388197818377224243341874299759393986316969168081293431967665057665354002144386679806241726680717167432197115393709044305367801562368377199313542622242088334493968227031303600659164182705200363370843349892071172286671217348220799611979367426886573857836700695154474387375045676161964264719840020610569587332497543980147743876907161648026576356758480646523434992364261325929823041766729482733300160147897964050534385377467240755626731087578114754411412866113305365456719741211653254865891742861999731525476635260033457850071277557432915055294927970289560714643822194080384022366782758886009197";
    var exp = "65537";

    var sha_1 = CryptoJS.SHA1(password);
    var SHA3_512_password_salted = new jsSHA("SHA3-512", "HEX");
    SHA3_512_password_salted.update(sha_1 + salt);

    var BigInteger = forge.jsbn.BigInteger;
    var n = new BigInteger(mod);
    var e = new BigInteger(exp);
    
    var publicKey = forge.pki.setRsaPublicKey(n, e);
    var encrypted = publicKey.encrypt(SHA3_512_password_salted.getHash("BYTES"), 'RSA-OAEP', {
        md: forge.md.sha256.create(),
        mgf1: {
            md: forge.md.sha1.create()
        }
    });

    return forge.util.bytesToHex(encrypted);
}

console.log(returnSignature())

The outputs are as follows:

python (too long):

00d86c34de01be954a7c578dc172dccc4331290e3b1424be4934fd60f0f465f7816fcf43021f85d46b914699bb4b43225bfce801779be65e2c6b06e5fc08677e87b36a3cc4f98b98ca308ecb296bb6958b36b962ba470e54f362d39449e7ed19d99ad6aba53c8930ea1491ca4812d0115a6147cb7598bb170cd5cbd8aeca9f613600ae0894fe99471c71b1a9b70374e93b77ec56638aa89c0fdeb2405d74b1c3de8e100bcfe912a50b6c51a9657e4dc1c368e2a3879e1b719120711e94263d29b4f35644e9625ccfbd476c7398b84bdce22553f14a42a38145a4bb5b588a921e55c0255dd16edca5c76106d131ef86a6b5ec961e6991e03f2c4433bfce95924a0e80b1dba8f45126080a1b971d2200d01325cf7a88a783c5fd99d8842308c25bdda1bd7ab18b7e2701506b55d70c3e2c51f95937a9

Node (working):

5f40e08f1b81bca40b5b826ab29af7ca62d3c83050ed8d334f30a888b574b80e8ea58bae80c369ef0d2a819687ac078e7742e05c307f1d4b42c4dbfc2c8cc66633ebac840777af3b275a1f20ddf758cdcfdb6ec8ba8ba9b3f61d0bc26b976f8d3baf2d3909fff4b1f6cbd0f0c4350748fbd0385da06e0814fe82ac547bbb132231fdeb5612551f253f1fa96f4c37027a27663246d195a786c794485f41838be2db3999c65d3a6870715bc3cd47823d5001d12de9bed3616c74bba78235b1b11d2d0208341eb854fd9a56aee6ef1407f76911212a1fdd92c36e2860211a546533ef09242ec4ed9741176fc4bd1a7b3c75c1295b9b076410f9a0284397915c099d
  • 1
    `int(mod, 16)` parses `mod` as a base-16 number, but your Javascript is treating it as a base-10 integer. – chepner Apr 05 '22 at 15:05
  • changed to int(mod, 10) now the string lengths are matching, but still not working for some reason. – mikefreudiger Apr 05 '22 at 15:52
  • *...but still not working for some reason...* is not a proper error description! Anyway: The JavaScript code uses SHA256 as OAEP digest and SHA1 as MGF1 digest. In the Python code the default SHA1 is used for both digests, s. [`PKCS1_OAEP.new()`](https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html?highlight=mgf1#Crypto.Cipher.PKCS1_OAEP.new). You have to specify the digests in the Python code, s. e.g. [here](https://stackoverflow.com/a/65805979/9014097) how to do this. – Topaco Apr 05 '22 at 17:52
  • Sorry for the ambiguous error line, my string is not accepted by a third party app. Looks like you are the winner, changed this line and my password is accepted: encryptor = PKCS1_OAEP.new(publicKey, Hash.SHA256, mgfunc = lambda x,y: PKCS1_OAEP.MGF1(x, y, Hash.SHA1)) – mikefreudiger Apr 05 '22 at 19:12
  • @Topaco I owe you a I would not have figured that out on my own – mikefreudiger Apr 05 '22 at 19:13

0 Answers0