'Struggling to use C# RSA in Java

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?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source