1

I've been having trouble encrypting with an RSA public key. Here is a sample JUnit code that reproduces the problem:

public class CryptoTests {

private static KeyPair keys;

@BeforeClass
public static void init() throws NoSuchAlgorithmException{
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    SecureRandom random = CryptoUtils.getSecureRandom();
    keyGen.initialize(2176, random);
    keys = keyGen.generateKeyPair();
}
@Test
public void testRepeatabilityPlainRSAPublic() throws EdrmCryptoException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException{
    byte[] plaintext = new byte [10];
    Random r = new Random();
    r.nextBytes(plaintext);

    Cipher rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted1 =  rsa.doFinal(plaintext);

    rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted2 =  rsa.doFinal(plaintext);

    rsa = Cipher.getInstance("RSA");
    rsa.init(Cipher.ENCRYPT_MODE, keys.getPublic());
    byte[] encrypted3 =  rsa.doFinal(plaintext);

    assertArrayEquals(encrypted1, encrypted2);
    assertArrayEquals(encrypted1, encrypted3);
}
}

The result? The assertion fails.

Why is this behaviour seen here? As far as I remember from my crypto classes, any key can be used for encryption. Yet this is not what happens here. I've tested the same thing with the private key, and I get a repeatable output.

If, for some reason, RSA encryption with a public key is forbidden, then why am I not getting an exception?

What must I do to get repeatable results?

P.S. My JDK is 1.6.0_22 running on an Ubuntu 10.10 box.

2
  • P.S. I used the BouncyCastle provider and my tests are successful now. Commented Jan 21, 2011 at 12:09
  • That test succeeding is a really bad sign, since RSA encryption should be randomized. It's essential to use OEAP padding with RSA encryption. Neither textbook RSA nor PKCS#1 v1.5 padding are secure. Commented Jan 9, 2013 at 11:41

3 Answers 3

8

My guess is that it's applying randomized padding, precisely to make it more secure. From the RSA wikipedia page:

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.

...

To avoid these problems, practical RSA implementations typically embed some form of structured, randomized padding into the value m before encrypting it. This padding ensures that m does not fall into the range of insecure plaintexts, and that a given message, once padded, will encrypt to one of a large number of different possible ciphertexts.

Sign up to request clarification or add additional context in comments.

2 Comments

(+1) one minute faster, and an better explained than me
Yes -- what actually matters is whether it DECRYPTS to the same original plaintext.
1

You can confirm that what is happening is that random padding is being added by initialising your Cipher with the string "RSA/ECB/NoPadding". Now, you should see that the ciphertext is identical in each case (though for reasons stated by another answerer, you shouldn't really do this in practice).

Comments

0

To add extra detail to Jon's answer:

When you do Cipher.getInstance("...") you have a number of options, as you've probably gathered. The Standard Algorithm Names specify what these are.

The one you asked for, RSA is by default RSA under PKCS1, which, to quote the wikipedia article:

There are two schemes for encryption and decryption:

  • RSAES-OAEP: improved encryption/decryption scheme; based on the Optimal Asymmetric Encryption Padding scheme proposed by Mihir Bellare and Phillip Rogaway.
  • RSAES-PKCS1-v1_5: older encryption/decryption scheme as first standardized in version 1.5 of PKCS#1.

See RSALab's PKCS1 documentation for the detail of said padding schemes.

1 Comment

It's important to emphasize that RSAES-PKCS1-v1_5 allows practical attacks, so it should not be used. RSAES-OAEP is the way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.