participate


Cryptography - RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA [Locked]
This topic is locked
<<   Back to Forum  |   Give us Feedback
This topic has 9 replies on 1 page.
Dileep
Posts:12
Registered: 10/31/07
RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Nov 15, 2007 2:22 PM

 
Hi
Can some please help me here.
I have a requirement where I need to encrypt using JavaScript and decrypt in Java. Here is my sample code for this. I am using RSA with Bouncy Castle provider.


Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
		KeyPairGenerator RSAkeyPairGen = KeyPairGenerator.getInstance("RSA","BC");
		SecureRandom sunSha1prngSecRand = SecureRandom.getInstance("SHA1PRNG","SUN");
		sunSha1prngSecRand.setSeed(System.currentTimeMillis());
		// for demonstration purposes we generate a key-pair each time.
		//RSAkeyPairGen.initialize(1024,sunSha1prngSecRand);
		RSAkeyPairGen.initialize(128,sunSha1prngSecRand);
		rsaKeyPair = RSAkeyPairGen.generateKeyPair();
 
	RSAPrivateKey rsaPrivKey = (RSAPrivateKey) rsaKeyPair.getPrivate();
	String privateE = rsaPrivKey.getPrivateExponent().toString(16);
	String modulus = rsaPrivKey.getModulus().toString(16);
 
session.setAttribute("keyPair", rsaKeyPair);


I got the supporting JS files at http://www.ohdave.com/rsa/.
Most of the cases it works perfect. But few times it throws org.bouncycastle.crypto.DataLengthException: input too large for RSA.
I see there are some posting abott this error and I am not able to incorporate in this code to work. I also noticed if the encrypted first byte is >8 (i.e 8,9,a,b,c,d,e) the error occurs else it works perfect. I really appreciate if some one can help me.

Javascript Code :

setMaxDigits(76);
key = new RSAKeyPair("<%=privateE%>", "", "<%=modulus%>");
document.secretform.secret.value = encryptedString(key, document.secretform.secret.value);


Here is the decrypted code :


KeyPair rsaKeyPair = (KeyPair) session.getAttribute("keyPair");
	String secret = request.getParameter("secret");
	out.println(rsaKeyPair+"secret:"+secret);
	
	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
	PublicKey rsaPubKey = rsaKeyPair.getPublic();
		
	Cipher decrypt = Cipher.getInstance("RSA","BC");
	decrypt.init(Cipher.DECRYPT_MODE,rsaPubKey);
	// if data encrypted was too long on browser, it has been chunked into
	// separately encrypted pieces - separated by space.
	String[] chunks = secret.split(" ");
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	for (int i = chunks.length-1; i >= 0; i--) {
		BigInteger iSecret = new BigInteger(chunks[i], 16);
		byte[] ciphertext = iSecret.toByteArray();
		//decrypt.update(ciphertext);
		byte[] buf = decrypt.doFinal(ciphertext);
		baos.write(buf);
	}
	byte[] decrypted = baos.toByteArray();
	String value = new String(decrypted, "UTF-8");
	// for some reason, with the javascript package the value is getting reversed?
	StringBuffer sb = new StringBuffer(value);
	value = sb.reverse().toString();
	
	out.println("Decrypted Value:"+value);


Edited by: Dileep on Nov 15, 2007 2:21 PM
 
Dileep
Posts:12
Registered: 10/31/07
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for   
Nov 18, 2007 5:39 PM (reply 1 of 9)  (In reply to original post )

 
Please let me know if some one has an idea of this where can
encrypt on client side javascript and decrypt on java server side.
PLease read the above post before you come here.
I want to use asymmetrical algoritham, because I want to encrypt
with the one key(generated by server side) on javascript side
and decrypt with different one.

I am using RAS for this(code is in the above post) and I am getting
padding issue as the javascript is not implemented with padding.
Tough i got the javascript code with padding at below link, Its not
working proper and not sure what padding is that.

http://translate.google.com/translate?hl=en&sl=it&u=http://blogs.ugidotnet.org/rgm/archive/2007/10/24/89174.aspx&sa=X&oi=translate&resnum=1&ct=result&prev=/search%3Fq%3D%2Bvar%2BBlockLength%2B%253D%2B(i%2B%252B%2Bkey.chunkSize)%2B%253E%2Bal%2B%253F%2Bal%2B%2525%2Bkey.chunkSize%2B:%2Bkey.chunkSize%253B%26hl%3Den%26sa%3DG

Thanks
Dileep
 
ed_hager
Posts:2
Registered: 10/28/05
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for   
Jul 29, 2008 3:07 PM (reply 2 of 9)  (In reply to #1 )

 
Ok, this thread is a bit old and I would hope by now that Dileep solved his problem. But, if you are like me and working on the same kind of problem and experiencing the " input too large" error only some of the time, then read on...

Do not use BigInteger to convert your encrypted string into a byte array like Dileep was doing:

BigInteger iSecret = new BigInteger(chunks[i], 16);
byte[] ciphertext = iSecret.toByteArray();


I was using BigInteger and I noticed that if the high bit was set on my encrypted data, then I would get the "input too large" error. For example, if my encrypted data string started with something like "a55bfe..." I would get the error. I would change the first digit to a "7", "755bfe.." and my code would decrypt the string.

I looked at the byte array being generated by BigInteger.toByteArray(). What was happening is the array size would be increased in size to a multiple of 4. If the high bit of my encrypted string was not set, then no problem, the extra bytes were zero. But, if the high bit was set, then the sign would be extended into the extra bytes giving them non zero values. This causes the byte array to be larger than what your key length allows.

My solution was to stop using BigInteger and write my own code that converted the hex string into a byte array. Something like this:

byte[] hexStringToByteArray(String data) {
		int k = 0;
		byte[] results = new byte[data.length() / 2];
		for (int i = 0; i < data.length();) {
			results[k] = (byte) (Character.digit(data.charAt(i++), 16) << 4);
			results[k] += (byte) (Character.digit(data.charAt(i++), 16));
			k++;
		}
 
		return results;
	}


Once I did that, everything worked fine.
 
evan2nave
Posts:3
Registered: 9/4/09
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 4, 2009 11:44 AM (reply 3 of 9)  (In reply to original post )

 
Hello Dileep,

I am dealing with a very similar issue and was hoping you might be able to help. Thank you in advance for your time!

I am trying to use a public key to rsa encrypt (1024 bit keysize) something in a javascript client that I then try to decrypt in my java server side application. There are other reasons why I am not just submitting the data with ssl (it's a cross domain ajax submit from a widget and I can't post to the server). Anyway, let's just assume that I have to do this encryption in the javascript and decryption in the java.

I have tried a few javascript libraries, including the one referenced in this thread from http://www.ohdave.com/rsa/. I have also tried using both the standard jdk 1.5 api, as well as addtionally the BouncyCastle provider, to generate the public and private key values, as well as to do the server-side decryption. I can sucessfully both encrypt and decrypt together in the java server side. However, when I encrypt with the javascript, in various formulations, I have faced errors such as it telling me the input is too large, or other padding related errors like it says it expects the input to be starting with a 0. I have called Cipher.getInstance("RSA","BC"); as well as Cipher.getInstance("RSA/ECB/PKCS1Padding"); and Cipher.getInstance("RSA/ECB/NoPadding");

At the moment, using the BC provider, I am not getting a specific error, but the decrypted value it creates is still completely jumbled data, rather than the correct starting plaintext data.

I was wondering if you might have any other insights into how I can determine what is going wrong. Did you ultimately use the javascript library from ohdave.com compatibly with your java code? Did you have to specify an alternate encodings, or just "RSA", "BC"?

If you could possibly provide a snippet of the javascript encryption code and compatible java key generation and decryption code, perhaps with just a hardcoded data message, that would be amazing! But any pointers would be greatly appreciated.

Thank you so much for your time and help,
-Evan
 
ghstark
Posts:1,032
Registered: 4/30/00
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 4, 2009 3:14 PM (reply 4 of 9)  (In reply to #3 )

 
You cannot ignore the padding issue, even though it may be confusing. RSA operations occur using large integer arithmetic. Your javascript code must have some technique of moving from a javascript object to an integer that is less than the modulus. It then must perform the RSA operation, the output of which is another integer less than the modulus. Finally, this must be converted to a sequence of bytes and sent to the peer. The Java peer must now reverse these steps in 100% compatible way. There are maybe 10 places things can go wrong in here.What are you encrypting? If it is a string, how it encoded into bytes? Are you verifying that it is not too big? RSA cannot be used to encrypt more data than the modulus size. How is it encoded into a big integer? How is the RSA result converted into a byte sequence? Is it big or little endian? How are the keys represented?
 
sabre150
Posts:21,537
Registered: 10/24/97
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 5, 2009 12:03 AM (reply 5 of 9)  (In reply to #4 )

 
ghstark wrote:
You cannot ignore the padding issue, even though it may be confusing. RSA operations occur using large integer arithmetic. Your javascript code must have some technique of moving from a javascript object to an integer that is less than the modulus.

The JS RSA code cited seems not to use padding and to use the flawed technique for RSA encrypting data of length greater than the modulus of splitting the data into chunks of the modulus length and individually encrypting them. The PASCAL RSA code provided on the same page as the JS seems to do the same.

It then must perform the RSA operation, the output of which is another integer less than the modulus. Finally, this must be converted to a sequence of bytes and sent to the peer. The Java peer must now reverse these steps in 100% compatible way. There are maybe 10 places things can go wrong in here.What are you encrypting? If it is a string, how it encoded into bytes? Are you verifying that it is not too big? RSA cannot be used to encrypt more data than the modulus size. How is it encoded into a big integer? How is the RSA result converted into a byte sequence? Is it big or little endian? How are the keys represented?
 
evan2nave
Posts:3
Registered: 9/4/09
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 5, 2009 3:21 PM (reply 6 of 9)  (In reply to #5 )

 
Thanks for the responses. I understand that there are various layers where the encoding can go wrong, and it sounds like you are saying that the javascript code provided on ohdave.com is also improperly breaking the data into chunks. In that case, is anyone aware of any other existing javascript libraries that would be able to rsa encrypt a string in a fully compatible way to a java server-side decryption like what I describe below? Or do you think it is necessary to delve into the javascript code itself to modify encoding details. I am really hoping that sufficient existing libraries exist, or I can use one with really minimal tweaking.

Here's what I'm doing on the java side, so you can see how I'm representing everything.

First, to generate the public & private keys, I've got the following code:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();

KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey, RSAPrivateKeySpec.class);

saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());

The saveToFile method is very simple, taking parameters "fileName", "mod", and "exp", and serializing the objects with a couple lines of code:
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
oout.writeObject(mod);
oout.writeObject(exp);

I also have this process print out the public key mod and exponent as hex strings, because it seemed like that was what I needed to hardcode into the javascript. If a different library needs this in some other form, I can change this as necessary to get the values to hardcode into the javascript. At this stage I just need proof of concept, and I can hardcode things as necessary.
System.out.println("mod="mod.toString(16));
System.out.println("exp="+exp.toString(16));

For the decryption, I was assuming that I was starting with a string representing hexadecimal because that was what it looked like I was getting from the javascript library I was using. I can change this if necessary, but below is basically what I've been doing... I'm leaving out the ajax code for how my client and server are communicating, and for now, I'm simply having the javascript print the encrypted value to the screen and I'm pasting it into my decryption code (below is just an example with one hex message that was the output of my javascript printing the encrypted value:

String hex = "80ed8ec9ae3af37d7d9ea807eb8988c3f85231efd97dcc219bedc63492b9c83cd9f3a67795e287aa145f019607ef8c566bbc76896afa66911925f871c8c036f14f72ed1e1899eaa9f1e4eb8cdc039350af96ea8adfd852e0997cbe58aa2de8dfd3ad11e0689be855ce27548df72733ba8fbdc4ae52c6ff57baab1a02f1082c3b";

byte[] encBytes = new BigInteger(hex, 16).toByteArray();
PrivateKey privKey = readPrivateKeyFromFile("/private.key"); // this is just a simple reversal of the serialization from before
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // (also tried this with RSA/ECB/NoPadding)
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data);
System.out.println("decrypted string: "
new String(cipherData));


Can I do something pretty much along these lines in the java and have some javascript encryption work compatibly with this, without needing to re-implement the javascript all on my own. If anyone knows of a javascript library that can successfully work with this, perhaps with a sample proof-of-concept code snippet, that would be extremely helpful!

Thanks again for any help!
-Evan
 
sabre150
Posts:21,537
Registered: 10/24/97
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 5, 2009 10:34 PM (reply 7 of 9)  (In reply to #6 )

 
evan2nave wrote:
Thanks for the responses. I understand that there are various layers where the encoding can go wrong, and it sounds like you are saying that the javascript code provided on ohdave.com is also improperly breaking the data into chunks.

That is my view. The technique can fail for a block of ciphertext that has a leading zero unless the care is taken to preserve the leading zero. The last block could consist of just one byte and
RSA encrypting just one byte or even just a few bytes is a no-no since it is almost trivial to break and without padding such as PKCS1 there is ambiguity when decrypting.

RSA should only be used to encrypt a small amount of data such as a random secret session key to key. This session key should then be used with a symmetric encryption algorithm such
as AES. The session key needs to be padded using something like PKCS1 .

In that case, is anyone aware of any other existing javascript libraries that would be able to rsa encrypt a string in a fully compatible way to a java server-side decryption like what I describe below? Or do you think it is necessary to delve into the javascript code itself to modify encoding details. I am really hoping that sufficient existing libraries exist, or I can use one with really minimal tweaking.

It is not the RSA library you need but the BigInteger since RSA is almost trivial to implement given a BigInteger library. You will then need routines for padding (say PKCS1) and you will
need a Javascript symmetric algorithm implementation such as AES or maybe even Blowfish or DES.


Here's what I'm doing on the java side, so you can see how I'm representing everything.

First, to generate the public & private keys, I've got the following code:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();

KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey, RSAPrivateKeySpec.class);

saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());

The saveToFile method is very simple, taking parameters "fileName", "mod", and "exp", and serializing the objects with a couple lines of code:
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
oout.writeObject(mod);
oout.writeObject(exp);

Please use the CODE tags when posting code. It makes the code easier to read and stops the stupid forum markup language from interpreting code as markup.

I'm not keen on the use of Java object serialization for this. You need your keys to be readable outside of Java i.e. in Javascript.

I also have this process print out the public key mod and exponent as hex strings, because it seemed like that was what I needed to hardcode into the javascript.

Absolutely. It never makes sense to use basic Java serialization when communicating with non-Java code.

If a different library needs this in some other form, I can change this as necessary to get the values to hardcode into the javascript. At this stage I just need proof of concept, and I can hardcode things as necessary.
System.out.println("mod="mod.toString(16));
System.out.println("exp="+exp.toString(16));

For the decryption, I was assuming that I was starting with a string representing hexadecimal because that was what it looked like I was getting from the javascript library I was using. I can change this if necessary, but below is basically what I've been doing... I'm leaving out the ajax code for how my client and server are communicating, and for now, I'm simply having the javascript print the encrypted value to the screen and I'm pasting it into my decryption code (below is just an example with one hex message that was the output of my javascript printing the encrypted value:

String hex = "80ed8ec9ae3af37d7d9ea807eb8988c3f85231efd97dcc219bedc63492b9c83cd9f3a67795e287aa145f019607ef8c566bbc76896afa66911925f871c8c036f14f72ed1e1899eaa9f1e4eb8cdc039350af96ea8adfd852e0997cbe58aa2de8dfd3ad11e0689be855ce27548df72733ba8fbdc4ae52c6ff57baab1a02f1082c3b";

byte[] encBytes = new BigInteger(hex, 16).toByteArray();

Does not preserve leading zeros. Use a Hex decoder such a the one available in Jakarta Commons Codec.

PrivateKey privKey = readPrivateKeyFromFile("/private.key"); // this is just a simple reversal of the serialization from before

Check the resulting key against the original. Check again and then again because if this is wrong nothing will work.

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // (also tried this with RSA/ECB/NoPadding)

Since your Javascript did not do PKCS1 padding, this will not work. You have to use padding in your Javascript.

Also, since the flawed Javascript breaks the cleartext into blocks the size of the modulus, you must reverse this process.

cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(data);
System.out.println("decrypted string: "
new String(cipherData));



Can I do something pretty much along these lines in the java and have some javascript encryption work compatibly with this, without needing to re-implement the javascript all on my own. If anyone knows of a javascript library that can successfully work with this, perhaps with a sample proof-of-concept code snippet, that would be extremely helpful!

There is a whole load of stuff here but I can't vouch for the quality.
 
evan2nave
Posts:3
Registered: 9/4/09
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for RSA   
Sep 10, 2009 11:11 AM (reply 8 of 9)  (In reply to #7 )

 
thank you very much for your thoughtful response. I'm still working on modifying the javascript, but your pointers are very helpful.
-Evan
 
kajbj
Posts:28,559
Registered: 3/21/00
Re: RSA -- org.bouncycastle.crypto.DataLengthException: input too large for   
Sep 12, 2009 4:58 AM (reply 9 of 9)  (In reply to #8 )

 
I'm now locking this zombie thread.

Kaj
 
This topic has 9 replies on 1 page.
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics

About Sun forums
  • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

    Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

Powered by Jive Forums