5

Hi this is the same question, that was asked two years ago: Java/JCE: Decrypting “long” message encrypted with RSA

I had a large byte array and rsa keypair, initiated by value 1024. Using rsa encryption and the specified size of the key is strong requirement, I can't change it. So I can't use symmetric encryption with asymetric encryption symmetric key. I can't use any other keys. I had a byte array and need ciphered byte array to be returned. I wonder if there is any ready tool, that can manage with this problem?

Sorry for such an amateurish question, but I really need a help.

Community
  • 1
  • 1
Denis
  • 1,130
  • 3
  • 17
  • 32

2 Answers2

14

As stated, your question has a single answer, and that's "no". RSA encryption is an algorithm which encrypts messages up to a given size, which depends on the key size; with a 1024-bit RSA key, and RSA as the standard describes it, the maximum size is 117 bytes, no more. There is no way to encrypt a larger message with RSA alone, and that's a definite, mathematical certainty.

If you really need to process longer messages, then you necessarily have to add something else. In that case, please, please, do not try to do anything fancy of your own devising with some oh-so-clever splitting of data into small blocks and the like. That path leads to doom. You might produce something which appears to compile and run, but which will be invariably weak in some way, like almost every other home-made variation on cryptography. That's because security cannot be tested: it is not a case of "works" or "does not work".

The well-trodden path of asymmetric encryption goes thus:

  1. You select a random sequence of bytes of some appropriate length, e.g. 128 bits (that's 16 bytes). Let's call it K.
  2. You encrypt K with the RSA public key; this yields E.
  3. You encrypt the message with K using a symmetric encryption algorithm ("AES/CBC/PKCS5Padding"). Since this is a one-shot key, you can use an all-zeros IV. This yields a bunch of bytes, let's call it F.
  4. The encrypted message is then the concatenation of E and F.

Decryption proceeds in the reverse order: the RSA private key is used to recover K from E, then K is used to decrypt F into the original message. The key K is never stored anywhere, and a new key K is generated every time (even if you encrypt the same message twice). That's important, do not change that unless you understand what you are doing (and if you do, then you already know that).

Given what you state about your problem, you have to do something else than "just RSA". The procedure I describe above is about the best "something else" that you could come up with, security-wise.

Assembling some cryptographic elements into such a protocol is a process fraught with pitfalls so you may have better luck using an already defined format and support library. Two common formats for asymmetric encryption are CMS and OpenPGP. A library which supports both and has good reputation is Bouncy Castle.

Community
  • 1
  • 1
Thomas Pornin
  • 72,986
  • 14
  • 147
  • 189
  • 1
    Good answer. Nothing more to add. – St.Shadow Apr 16 '10 at 16:10
  • Its a pity, that I can't change the specification. – Denis Apr 16 '10 at 16:59
  • It might just be a matter of how you *interpret* the specification. If it just says "The data should be encrypted using a 1024 bit RSA key", then Thomas' answer is *the* standard way to do this, so I would argue that it is completely in agreement with the spec. – caf Apr 17 '10 at 01:45
  • -1. It is well known that this encryption mode is not secure. It is susceptible to a chosen ciphertext attack. Either use OAEP padding rather than the old PKCS#1 padding or better use some authentication. – Accipitridae Apr 18 '10 at 11:26
  • Also Bouncy Castle isn't that great either. It still has significant unpatched flaws in it implementation of RSA. – Accipitridae Apr 18 '10 at 11:27
  • If it is "well known" that PKCS#1 v1.5 padding is "insecure" and "susceptible to a chosen ciphertext attack", then maybe you could provide a reference supporting that assertion ? – Thomas Pornin Apr 19 '10 at 12:52
  • The very same paragraph in which PKCS#1 (2.0) talks about the Bleichenbacher attack on the v1.5 padding also states that there are a few countermeasures which are very effective in thwarting the attack, without changing a single bit in the padding or encryption process (and that's what any decent SSL implementation does, by the way). The v1.5 padding is not insecure; what is insecure is non-binary error reporting on failed operation. The same kind of attack actually applies to OAEP, see: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.104.1841&rep=rep1&type=pdf – Thomas Pornin Aug 01 '10 at 15:21
3

If you do need to encrypt/decrypt long strings using RSA, then you can break the bytes up in to smaller "chunks" and process each chunk of bytes through the cipher one at a time while storing the results in a ByteBuffer.

Encryption:

byte[] encData = null;
try {

    // create public key
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(key);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    PublicKey pk = kf.generatePublic(publicKeySpec);

    Cipher pkCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    pkCipher.init(Cipher.ENCRYPT_MODE, pk);

    int chunkSize = 117; // 1024 / 8 - 11(padding) = 117
    int encSize = (int) (Math.ceil(data.length/117.0)*128);
    int idx = 0;
    ByteBuffer buf = ByteBuffer.allocate(encSize);
    while (idx < data.length) {
        int len = Math.min(data.length-idx, chunkSize);
        byte[] encChunk = pkCipher.doFinal(data, idx, len);
        buf.put(encChunk);
        idx += len;
    }

    // fully encrypted data     
    encData = buf.array();
} catch (Exception e) {
    e.printStackTrace();

Decryption

Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsaCipher.init(Cipher.DECRYPT_MODE, rsaPk);

int chunkSize = 128;
int idx = 0;
ByteBuffer buf = ByteBuffer.allocate(data.length);
while(idx < data.length) {
    int len = Math.min(data.length-idx, chunkSize);
    byte[] chunk = rsaCipher.doFinal(data, idx, len);
    buf.put(chunk);
    idx += len;
}

// fully decrypted data
byte[] decryptedData = buf.array();
Aaron Wilson
  • 51
  • 1
  • 4
  • 1
    One should never do such a chunked RSA encryption/decryption. It is error prone, insecure and horribly slow for longer messages. – Artjom B. Mar 15 '16 at 22:39
  • A lot of messages here say what not to do. It would be nice to at least mention what to look for. Right now I look for some information how to do things. What I know now is RSA is for encrypting key of symetric algorithm, AES for example. – Pochmurnik Oct 08 '20 at 12:41