2

I'm not a crypto-guy so I know close-to-zero about these things. I must interoperate with a system using RSA cryptography. When using their keys, I'm running into the problem of getting different ciphers for the same input/key. The library is https://code.google.com/p/pajhome/source/browse/trunk/crypt/md5/rsa/RSA.js?r=133 and I'm using the Java BouncyCastle RSA Provider as follows:

BigInteger e = new BigInteger("9d7aa162117a8a9610ed2ddea713d7b", 16);
BigInteger m = new BigInteger("c9869917572adbb60a2c30ddec2551f", 16);

RSAPublicKeySpec spec = new RSAPublicKeySpec(m, e);
KeyFactory keyFac = KeyFactory.getInstance("RSA", "BC");
PublicKey pubKey = keyFac.generatePublic(spec);

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

// UNENCRYPTED_LOGIN = "201211130215"
// UNECRYPTED_TYPE = "1"

byte[] login = cipher.doFinal(UNENCRYPTED_LOGIN.getBytes("ASCII"));
byte[] type = cipher.doFinal(UNENCRYPTED_TYPE.getBytes("ASCII"));

// login = 00d571a40ef7359b2e9e10b7c5dd621c
// should be 02f0cc389fb88e6b4aaa4e2477858ca9

// type = 0a5c2e176c81b23b2e1dd635f2427c0f
// it is correct
Délisson Junio
  • 1,296
  • 4
  • 21
  • 43
  • Try encrypting something with two digits, say "11" or "12" and see if the discrepancy is there. If not, keep adding digits until it shows up. The JS algorithm seems to be doing some sort of packing that the Java library likely doesn't do. – mikeazo Sep 15 '14 at 15:06
  • It breaks with more than one character. From 0 to 9, the output is the same. – Délisson Junio Sep 15 '14 at 15:19
  • Those numbers and everything else here is quite sketchy. The modulus is trivially factorable (37 is a factor!!) and the javascript code is uncommented and hard to figure out. You aren't really using Bouncycastle except for the key factory, and I don't see why you need Bouncycastle anyway. You'll probably need to get an RSA instance with "NOPADDING" specified for padding, then implement the padding yourself to match the javascript. Or just use the javascript yourself and skip the java altogether. – President James K. Polk Sep 16 '14 at 01:28
  • The Sun JVM's default RSA implementation wouldn't allow me to use such small key sizes. The fact is I need this exact method and data for logging in another system which is completely out of my control, so I don't know how to do it without being insecure about it, as the original service is just as flawed. – Délisson Junio Sep 16 '14 at 01:40

1 Answers1

1

The issue is the packing method from lines 52 to 65 in the JS source you linked to. It works for 1 character strings, but will have problems when doing larger strings.

To illustrate the problem, consider what is happening with a length 1 string. The JS code creates an array and puts the ascii value of the character in the array. Then pads the array with zeros. The packing algorithm builds a new array by packing 2 of the array elements into a single value in a new array. It does something like this:

for i=0, i<len(old_array), i+=2:
  new_array[i] = old_array[i] + (old_array[i+1] << 8)

For a length 1 input string (say it is "1"), you would have old_array=[0x31, 0x00,...] (some more zero padding). So new_array=[0x31 + (0x00 << 8 == 0x00) = 0x0031, ...] (more zero padding). Notice that old_array == new_array (to some extent, new_array is actually shorter, but it is all zeros anyways, so the value when converted to a big integer is the same).

With a length 2 input string (say "12"), you would have old_array=[0x31, 0x32, 0x00, ...] (more padding). So new_array=[0x31 + (0x32 << 8 == 0x3200) = 0x3231, 0x0000]. Notice that this is not the same as old_array.

Therefore, to fix your problem, you need to implement the packing. Then encrypt the packed array.

The JS library also does one other thing that you aren't doing, which may or may not be an issue. If your plaintexts get too long, the JS library breaks them up and encrypts them separately (this is the chunk size in the JS library).

mikeazo
  • 389
  • 2
  • 24