6

I'm trying to port the following Java code to a C# equivalent:

public static String encrypt(String value, String key) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    byte[] bytes = value.getBytes(Charset.forName("UTF-8"));
    X509EncodedKeySpec x509 = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(key));
    KeyFactory factory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = factory.generatePublic(x509);
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    bytes = cipher.doFinal(bytes);
    return DatatypeConverter.printBase64Binary(bytes);
}

So far I managed to write the following in C#, using the BouncyCastle library for .NET:

public static string Encrypt(string value, string key)
    {
        var bytes = Encoding.UTF8.GetBytes(value);
        var publicKeyBytes = Convert.FromBase64String(key);
        var asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
        var rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter;
        var cipher = CipherUtilities.GetCipher("RSA");
        cipher.Init(true, rsaKeyParameters);
        var processBlock = cipher.DoFinal(bytes);
        return Convert.ToBase64String(processBlock);
    }

The two methods, though, produce different results even if called with the same parameters. For testing purposes, I'm using the following public RSA key:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItTMjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCuFUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB

Could you please help me to port the Java code successfully or suggest an alternative to get the same result in C#?

EDIT1: output in Java is different each time I run the program. I don't think that any padding was specified, so I don't understand what makes the output random.

EDIT2: Java uses PKCS1 by default, so it was enough to specify it in the C# cipher initialization to get the same encryption type (although not the same result, which was irrelevant at this point).

user1098567
  • 339
  • 3
  • 9
  • More just wondering, but despite the fact they spit out different answers, do they give the same inputs when you decrypt them? – dann.dev Jun 14 '12 at 23:48
  • Yeah, the UTF8-decoded strings are the same and apparently the modulus and exponent of the two key structures (PublicKey in Java, RsaKeyParameters in C#) are identical. I don't try to decrypt the results as I don't need it and the program does not require the private key. – user1098567 Jun 15 '12 at 00:11
  • 2
    Duplicate? http://stackoverflow.com/questions/4758321/java-rsa-encryption-non-repeatable – Jf Beaulac Jun 15 '12 at 00:46
  • 2
    Can you try specifying RSA/ECB/NoPadding for both java and C#? – pd40 Jun 15 '12 at 01:12
  • 1
    @pd40 I testet it for fun. It gives the same output in both C# and Java. – MAV Jun 15 '12 at 01:39
  • Solved, to get the same output of Java code I had to specify "RSA/NONE/PKCS1Padding" in the C# cipher init. Thanks for the help. – user1098567 Jun 15 '12 at 09:10
  • Maybe this could help you put too? http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.71).aspx – David Kroukamp Jun 15 '12 at 22:28
  • For security purposes PKCS#1 specifies random padding for this kind of operation. The output is supposed to be different every time. – President James K. Polk Jun 16 '12 at 00:01

1 Answers1

1

As an educated guess, I would say that Java adds random padding to create a stronger encryption.

Most practical implementations of RSA do this, and as the wiki puts it...

Because RSA encryption is a deterministic encryption algorithm – i.e., has no random component – an attacker can successfully launch a chosen plaintext attack against the cryptosystem, by encrypting likely plaintexts under the public key and test if they are equal to the ciphertext. A cryptosystem is called semantically secure if an attacker cannot distinguish two encryptions from each other even if the attacker knows (or has chosen) the corresponding plaintexts. As described above, RSA without padding is not semantically secure.

This is likely why your two methods don't output the same.

James Williams
  • 678
  • 4
  • 14