Search code examples
javascriptjavanode.jstypescriptrsa

How to write the equivalent of this Java encryption function in the Node JS


This is the function used to encrypt in java

 public static String encryptionFunction(String fieldValue, String pemFileLocation) {
    try {

        // Read key from file
        String strKeyPEM = "";
        BufferedReader br = new BufferedReader(new FileReader(pemFileLocation));
        String line;
        while ((line = br.readLine()) != null) {
            strKeyPEM += line + "\n";
        }
        br.close();
        String publicKeyPEM = strKeyPEM;
        System.out.println(publicKeyPEM);
        publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
        publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");;
        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
        // byte[] encoded = Base64.decode(publicKeyPEM);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        PublicKey pubKey = (PublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] cipherData = cipher.doFinal(fieldValue.getBytes());
        if (cipherData == null) {
            return null;
        }
        int len = cipherData.length;
        String str = "";
        for (int i = 0; i < len; i++) {
            if ((cipherData[i] & 0xFF) < 16) {
                str = str + "0" + java.lang.Integer.toHexString(cipherData[i] & 0xFF);
            } else {
                str = str + java.lang.Integer.toHexString(cipherData[i] & 0xFF);
            }
        }
        return str.trim();

    } catch (Exception e) {
        System.out.println("oops2");
        System.out.println(e);

    }
    return null;
}

I want the equivalent of this in javascript/Nodejs, i tried this:

import * as NodeRSA from 'node-rsa';

private encryptionFunction(fieldValue: string , pemkey: string) : string {
    const rsa  = new NodeRSA(pemkey);
    const encrypted= rsa.encrypt(fieldValue , 'hex')
    return encrypted

}

But the output size of both functions is the same, but apparently the encryption type is wrong.


Solution

  • Node-RSA applies OAEP (here) as padding by default, so the PKCS#1 v1.5 padding used in the Java code must be explicitly specified. This has to be added after key import and before encryption:

    rsa.setOptions({ encryptionScheme: 'pkcs1' });
    

    Alternatively, the padding can be specified directly during key import:

    const rsa  = new NodeRSA(pemkey, { encryptionScheme: 'pkcs1' });
    

    With this change, both codes are functionally identical.


    Regarding testing: Keep in mind that RSA encryption is not deterministic, i.e. given the same input (key, plaintext), each encryption provides a different ciphertext. Therefore, the ciphertexts of both (functionally identical) codes will be different even if the input is identical. So this is not a bug, but the expected behavior.
    How then can the equivalence of both codes be proved? E.g. by decrypting both ciphertexts with the same code/tool.