I'm trying to replicate an existing C# application, part of which encrypts some data using a key.
Simple example:
using System;
using System.Security.Cryptography;
using System.Text;
public class Program {
private static string xmlKey = "<RSAKeyValue><Modulus>{REDACTED MODULUS}</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
public static void Main() {
RSACryptoServiceProvider cipher = new RSACryptoServiceProvider();
cipher.FromXmlString(xmlKey);
Console.WriteLine("KeyExchangeAlgorithm: " + cipher.KeyExchangeAlgorithm);
byte[] input = Encoding.UTF8.GetBytes("test");
byte[] output = cipher.Encrypt(input, true);
Console.WriteLine("Output: " + Convert.ToBase64String(output));
}
}
Which outputs:
KeyExchangeAlgorithm: RSA-PKCS1-KeyEx
Output: {THE ENCRYPTED OUTPUT}
I've replicated this in Java with the following, but while it runs ok, the downstream system can't decrypt the data, so I've done something wrong
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.KeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class Program {
// I tried "RSA/ECB/PKCS1Padding" but got "java.security.NoSuchAlgorithmException: RSA/ECB/PKCS1Padding KeyFactory not available at java.base/java.security.KeyFactory.<init>(KeyFactory.java:138)"
private static final String ALGORITHM = "RSA";
private static final String MODULUS = "{REDACTED MODULUS}";
private static final String EXPONENT = "AQAB";
// Converted from XML using
// https://superdry.apphb.com/tools/online-rsa-key-converter
private static final String PEM_KEY = "{REDACTED PEM KEY}";
public static void main(final String[] args) throws Exception {
final Cipher cipher = Cipher.getInstance(ALGORITHM);
final PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(getX509Key());
cipher.init(Cipher.ENCRYPT_MODE, key);
System.out.println("Algorithm: " + cipher.getAlgorithm());
final byte[] input = "test".getBytes(StandardCharsets.UTF_8);
final byte[] output = cipher.doFinal(input);
System.out.println("Output: " + Base64.getEncoder().encodeToString(output));
}
private static KeySpec getRSAKey() throws Exception {
return new RSAPublicKeySpec(base64ToInt(MODULUS), base64ToInt(EXPONENT));
}
private static BigInteger base64ToInt(final String str) {
return new BigInteger(1, Base64.getDecoder().decode(str.getBytes()));
}
private static KeySpec getX509Key() throws Exception {
return new X509EncodedKeySpec(Base64.getDecoder().decode(PEM_KEY));
}
}
Can anyone advise what I've done wrong, please?
Cipher.getInstance()is not the same as the algorithm string forKeyFactory.getInstance(). This is why it's critical to include the actual exception stacktrace copied and pasted into the question.