views:

123

answers:

6

I know its not the usual thing to do. But the specification I'm implementing is discribed this way, and I cannot run out.

I was trying to encrypt the modulus and exponent of the private key, but the following test code raises an exception because the byte array is 1 byte larger then the maximum allowed by RSA block:

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import javax.crypto.Cipher;

import org.apache.commons.lang.ArrayUtils;

public class TEST {

    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException {
 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
 keyPairGenerator.initialize(1024);
 return keyPairGenerator.generateKeyPair();
    }

    public static void main(String[] args) throws Exception {

 KeyPair keyPair = generateKeyPair();
 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

 System.out.println("Priv modulus len = " + privateKey.getModulus().bitLength());
 System.out.println("Priv exponent len = " + privateKey.getPrivateExponent().bitLength());
 System.out.println("Priv modulus toByteArray len = " + privateKey.getModulus().toByteArray().length);

 byte[] byteArray = privateKey.getModulus().toByteArray();
 // the byte at index 0 have no value (in every generation it is always zero)
 byteArray = ArrayUtils.subarray(byteArray, 1, byteArray.length);

 System.out.println("byteArray size: " + byteArray.length);

 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
 Cipher cipher = Cipher.getInstance("RSA", "BC");
 cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 byte[] encryptedBytes = cipher.doFinal(byteArray);

 System.out.println("Success!");
    }

}

(obs. its just a test, i would never encrypt the private key with its pair public key)

The byte array is 128 bytes, the exactly maximum allowed by a RSA block, so why the exception? And how to fix it?

EDIT: if I initilize the key pair generator with 1023 (instead of 1024) it works, but isn't the usual for RSA key size 1024?

A: 

The PKCS#1 method adds 11 bytes of checksums and padding, so your maximum plain-text size will be 117 bytes. See Too much data for RSA block fail. What is PKCS#7?

disown
I have just added to the question: if I initilize the key generator with 1023 instead of 1024 it works, so I don't think this 11 bytes are the problem... But I'm not sure if it is correct initialize it with 1023.
Tom Brito
Hmm, encryption is always trickier than you think... If the key you feed to the RSA has initial zeroes they will be truncated and you might be able to squeeze it in, does 1023 work consistently?
disown
so, how can i modify the above code to use PKCS#1 and have a maximum size of 117 bytes? (this size would fit well)
Tom Brito
Sorry, was confused. If you don't use padding you just have to make sure that the message satisfies 0 < m < n. A quick check with a byte size could be to check that the byte length of the input message is shorter than the modulus. This is probably what bouncy castle is checking. Just sum the byte lengths of p,q and n up and add one byte to the 'wrapping' encryption (if you want to encrypt (p,q,n)).
disown
and what about when I use java key generator to generate the key, and I don't know the p, q and n values (as in my example code)?
Tom Brito
you need to encrypt it with a longer, new, public key, not the old one.
disown
A: 

The amount of data you can encrypt in RSA is equal to the key size - 11 bytes. If you want to store more data, you should increase your key size from 1024.

Marcus Adams
strangely if I reduce the size (to 1023), the exception is not raised.. I don't know why.
Tom Brito
+1  A: 

Are you sure you need to do this? Most people encrypt symmetric keys with RSA key but encrypting RSA inside RSA doesn't buy you anything.

The maximum size of clear text can be encrypted by RSA is

  (key_size/8) - 11 bytes

So you can only encrypt 117 bytes for 1024-bit key. You need to use a much larger key to encrypt a smaller key.

ZZ Coder
Yes, sadly I need to encrypt the private key. I think will work if I encrypt the modulus and the exponent, the modulus is the problem, but it works if I initialize the key generator with 1023. But the specification says that the RSAs must be of size 1024.
Tom Brito
+1  A: 

If you absolutely want to use your own crypto protocol (which usually is not a good idea) then you could keep the public key (i.e. the modulus N and the public key e) as plaintext and simply encrypt one of the factors N. Since the facotors are about 512 bits for a a 1024 bit modulus, you should not have a problem with the encrytion. Knowing one of the factors and the public key is enough to determine the remainder of the private key.

Nonce
I don't want to use my own crypto protocol, I want to use RSA. (actually, I have to)
Tom Brito
He gave you a good answer but you wanted to argue with him.
GregS
+2  A: 

First: Someone has written this specification. Check with them instead of asking us. They have some reason for writing this requirement and you need to know what it is. When facing an unclear requirement the worst thing you can do is to begin guessing - especially when handling cryptography.

Second: in your test-code you are encrypting the private key modulus. The modulus is not secret in the RSA crypto-system, so there should be no need to encrypt this. You are not attempting to encrypt the private exponent (which is the actual secret part). The private exponent is always smaller than the modulus, so you should be able to encrypt it using the raw RSA operation (if you make sure to remove the prepended zero). This should be secure (translation: I do not see any obvious attacks considering it for 30 seconds) - if non-standard.

EDIT: As GregS points out in the comments, you cannot be sure that the private exponent of the key you want to encrypt is smaller than the modulus of the key you want to use to encrypt with. I think approximately 25% of the time this will not be the case. So use the method below instead.

An even better way to do it (which is completely standard and which I suspect is what the specification-writers actually intends) would be to encrypt the private key using the usual hybrid approach: Generate a symmetric key, use it to encrypt the private key (here you can use a standard serialized format without having to worry about the length), encrypt the symmetric key with the other public key (using RSA/PKCS#1) and transmit the two encryptions to the recipient who performs the opposite steps.

Rasmus Faber
+1 Better to ask twice if the specification is not quite clear.But, raw RSA operation should never be used by itself, it's insecure until you use a proper padding method, like OAEP.
Krystian
@Krystian: I realize that it is better to just always use proper padding, but in this case (large value of message, large message space, no chance of decryption-oracle) it should actually be as secure as PKCS#1-padding. Am I overlooking something?
Rasmus Faber
@Rasmus: Well, I don't have any attack at hand, but I would be scared to use it because of the algebraic structure. Your encrypted key would be d1^e2 mod N2 where (e1,d1,N1) are parameters of the first RSA and (e2,d2,N2) of the outer encryption. We know e1,N1, e2,N2. I guess depending on the relative values of N1,N2, e1, e2, there might be some trick that does nasty things... I've seen too many clever attacks to disregard this possibility.
Krystian
you're right about the exponent, and it fits in the block, so thanks.
Tom Brito
The private exponent is always smaller than *its* modulus, not necessarily someone else's.
GregS
@GregS: You are completely right. I have edited the answer.
Rasmus Faber
i cannot use the symmetric key approach (because of the project specification).
Tom Brito
by the way, thanks, it would be the right answer, but I have here a "special" project specification's case to handle.. :)
Tom Brito
A: 

The answer I was looking was (almost hidden) in the project's specification. Its to encrypt the rsa key by parts, and concatenate the parts. The same to decrypt (of course the size will need to be a default size known by encryptor and decryptor). This way I can use RSA without any symmetric key (not that I agree that this is the best encryption method).

Sorry trouble you guys (I tried to delete this question, but it cannot be deleted now).

Tom Brito
Please, consider leave a comment when downvoting.
Tom Brito