1

I'm having some trouble with using a public key from Java to encrypt within NodeJS.

I've created an RSA key within keytool and output the public key as a base64 encoded string.

Base64.Encoder encoder = Base64.getEncoder();
byte[] pubKeyBytes = publicKey.getEncoded();
String pubKeyBase64 = encoder.encodeToString(pubKeyBytes);

I then took the the base64 encoded public key, wrapped it in -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- and used it to encrypt, then base64 encode a string within node.

const encryptedBuffer = crypto.publicEncrypt(encodedPublicKey, buffer);
const encryptedEncodedText = encryptedBuffer.toString("base64");

When I try to decrypt the encryptedEncodedText (base64 decoding first) within Java, it throws a BadPadding exception. Interestingly, if I export the private key to a PEM, Node can't decrypt with it either.

Any help would be appreciated!

dardo
  • 4,870
  • 4
  • 35
  • 52
  • See this: https://stackoverflow.com/questions/8750780/encrypting-data-with-public-key-in-node-js – Sazzadur Rahaman Jul 14 '18 at 14:45
  • Yeah, I've tried that answer. I'm not sure what I'm missing from that post. – dardo Jul 14 '18 at 14:51
  • 1
    Also, if I use an OpenSSL public / private key, the encryption / decryption works fine in node, so I'm doing something wrong, or misunderstanding something from the Java side. – dardo Jul 14 '18 at 15:00

2 Answers2

2

After much searching and testing, it turned out to be a padding issue.

The public key provided to Node did was not being passed a passphrase, so it defaulted to RSA_PKCS1_OAEP_PADDING as per the documentation:

crypto.publicEncrypt

When decrypting on the Java side, it is necessary to inform Java of that padding as follows:

Cipher cipher = Cipher.getInstance("RSA/NONE/OAEPPadding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);

This fixed the issue, and allowed messages to be exchanged between Java and NodeJS.

dardo
  • 4,870
  • 4
  • 35
  • 52
1

I tried to reproduce your problem. For me, it works fine. I suspect the only problematic step can be when you are creating the PEM file manually. Be sure to:

  • If you are copying the key string from any console, remove unwanted characters from the beginning and/or end.
  • And a new line character (\n) after -----BEGIN PUBLIC KEY----- and before -----END PUBLIC KEY-----.

like below:

var key = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqwEldwNI5s1LkUzwyQZkPQQFpgtj29W7RcHgdwAbUOe31Q8bybAgzg5cUMqdIQlQHq6S5dxsSJBTDCZozSu+pxtKqRLz0JjtCTZD5gS+CJR9DlXH5GgJt+KDiO6olbKiVsP/tsMPgRCFKUMiMKU+dA06dwrUqJlC1k/JzuYVrbwIDAQAB\n-----END PUBLIC KEY-----"

var plaintext = "hello world"
var buffer = new Buffer(plaintext, "utf8")
console.log(crypto.publicEncrypt(key, buffer))

To avoid all these issues, you can directly generate PEM file from Java using the bouncycastle library.

Sazzadur Rahaman
  • 6,938
  • 1
  • 30
  • 52