1

I have a Java working sample app (which uses Bouncy Castle) that I need to port to C# (I'm using Bouncy Castle for C# too).

The code is almost the same. However, even when I provide exactly the same modulus and exponent for both, the result arrays are completely different also the strings.

Reiterating: The Java excerpt is the code that works

Where do I'm getting wrong? Thank you in advance!

Java:

public static String encodeRSA(String keyModulus, String keyExponent,
        String data) {
    try {

        byte btMod[] = Base64.decode(keyModulus);
        byte btExp[] = Base64.decode(keyExponent);

        BigInteger modulus = new BigInteger(1, btMod);
        BigInteger pubExp = new BigInteger(1, btExp);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, key);

        byte[] cipherData = cipher.doFinal(data.getBytes());
        String tmp = new String(Base64.encode(cipherData));

        System.out.println(tmp);

        return tmp;
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
    return "";
}

C#:

    private static string EncodeRSA(string modulus, string exponent, string data)
    {
        //Base64, DotNetUtilities functions and BigInteger type are from Bouncy Castle
        byte[] btMod = Base64.Decode(modulus);
        byte[] btExp = Base64.Decode(exponent);

        BigInteger mod = new BigInteger(1, btMod);
        BigInteger exp = new BigInteger(1, btExp);

        RsaKeyParameters bcKeySpec = new RsaKeyParameters(false, mod, exp);
        RSAParameters keySpec = DotNetUtilities.ToRSAParameters(bcKeySpec);

        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(keySpec);


        byte[] plaintext = Encoding.UTF8.GetBytes(data);
        byte[] ciphertext = rsa.Encrypt(plaintext, false);
        string cipherresult = Encoding.UTF8.GetString(Base64.Encode(ciphertext));
        return cipherresult;
    }

Modulus:

gdBAMJVXCuEGhX0b1hPAggpD7Ayi33JhsARksGkEatQsdox3BG3bTR/vz8M4vZe74EZj0aZrk0rGJGmAEJZ9GlXq6JzIRYBW5zULsBoPDq4spgobECJLsXq8CnZzOrOM+meIXFhoK8Jyob4X9q62HkDwhMMyqsBG0epWMHPIgkU=

Exponent:

AQAB

Output:

Java output for the entry "1]teste]111111]MTExMTExMTExMTExMTExMQ==" 
using the given modulus/exponent

dUCVsGrZIwSyh0ZAxon3wMSPPoQqflpRNtQ5c+TILuOR/5IihABJpZRL6E1TjYs62WXvQUbeFqRYbdAvbjY3YZk+aSviBosdN54+T8+/5agjveeDBi6LXu6r1+KBriq2K1ULg9YC62SrSbRN8VMJ9gkgatF2ux06PyouJOPJPN8=

EDIT - C# Output with given entry, modulus and exponent

CHyg5J+OMuG9H9S7R24Lg2iXeLN/Rgh7XcyDQJqMNZobH0V1hqe2dxrcE3R+UrVl/aDWJg3aXNtP3+8YFA17fLr9yIbIYv5o2zeRMdHbyrW/z26JGaynsay096KEzJ0uBAACJQ3LZryd5ei7zzo77Bnka2Un7C9TJvldswhldxM=
cezarlamann
  • 1,465
  • 2
  • 28
  • 43

1 Answers1

1

The output of RSA encryption, or any secure encryption method, outputs data that is indistinguishable from random to an attacker. This is performed by the IV for symmetric ciphers and by the padding method for RSA. If this wasn't the case then an attacker would be able to see similarities for different ciphertext; encrypt "yes" twice and the same ciphertext would appear. So an attacker could easily distinguish E(pk, "yes") | E(pk, "yes") from E(pk, "yes") | E (pk, "no").

So Java and C# both output a ciphertext that is precisely the size of the modulus before encoding. However the plaintext is first padded with secure random data before the modular exponentiation used for RSA. The way to verify that the ciphertext generation was correct is by decrypting the ciphertext using the private key. Actually, if you have multiple runs of either Java or C# you will find that the ciphertext keeps changing even within the same language/runtime.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thank you @MaartenBodewes for the clarification . About unit testing: If I ever need to write unit tests for encryption methods like this one (for encrypting), I'll roughly depends on a previously known decryption method and vice-versa? Is there a way to code reliable unit tests for encryption methods? – cezarlamann May 27 '15 at 14:54
  • 1
    Well, as you would be using test keys (I hope) you should always be able to encrypt decrypt. I would however mainly test the correctness of input/output handling. RSA itself should be tested by the platform. You should of course have one or two tests to test that there is no catastrophic failure on the platform, i.e. test that 2 encryptions have different ciphertext and that a single encrypt/decrypt works correctly. Otherwise: bounds checking, state checking etc. etc. should keep you occupied. – Maarten Bodewes May 27 '15 at 15:00