Encrypt with the RSAPublic key contained in a byte[]

Hello, i need a way to put the RSAPublicKey i receive from server(byte[128]) into a correct object to invoke to the .init method of Cipher properly, the code is:

private doEncrypt (byte[] toEncrypt,byte[] key){

Cipher rsa = Cipher.getInstance("RSA/ECB/nopadding");

rsa.init(Cipher.ENCRYPT_MODE, key);/*can`t use it because parameters must be

(int opmode, Key key) and i have (int opmode, byte[] key)*/

byte[] encripted = rsa.doFinal(toEncrypt);

}

i think it cant be very difficult but im getting crazy :S, thanks in advance :)

[817 byte] By [jbeata] at [2007-11-26 23:52:55]
# 1
128 bytes does not seem enough. That is 1024 bits but I suspect that that is just the modulus. What about the exponent?
sabre150a at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 2

Thanks for the quick answer, i really dont know very much about criptographic concepts ( i mean modulus and exponent)

not enough? the server only send 128 i know for sure im looking at the source code of it and transform the modulus of the public key in a byte array and then make some xor operations, this is the code:

private byte[] scrambleModulus(BigInteger modulus)

{

byte[] scrambledMod = modulus.toByteArray();

if (scrambledMod.length == 0x81 && scrambledMod[0] == 0x00)

{

byte[] temp = new byte[0x80];

System.arraycopy(scrambledMod, 1, temp, 0, 0x80);

scrambledMod = temp;

}

// step 1 : 0x4d-0x50 <-> 0x00-0x04

for (int i = 0; i < 4; i++)

{

byte temp = scrambledMod[0x00 + i];

scrambledMod[0x00 + i] = scrambledMod[0x4d + i];

scrambledMod[0x4d + i] = temp;

}

// step 2 : xor first 0x40 bytes with last 0x40 bytes

for (int i = 0; i < 0x40; i++)

{

scrambledMod[i] = (byte) (scrambledMod[i] ^ scrambledMod[0x40 + i]);

}

// step 3 : xor bytes 0x0d-0x10 with bytes 0x34-0x38

for (int i = 0; i < 4; i++)

{

scrambledMod[0x0d + i] = (byte) (scrambledMod[0x0d + i] ^ scrambledMod[0x34 + i]);

}

// step 4 : xor last 0x40 bytes with first 0x40 bytes

for (int i = 0; i < 0x40; i++)

{

scrambledMod[0x40 + i] = (byte) (scrambledMod[0x40 + i] ^ scrambledMod[i]);

}

_log.fine("Modulus was scrambled");

return scrambledMod;

}

and then, it sends to me

any idea of how to reverse this process? :)

jbeata at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 3

The code for getting the RSA key in the RSAPublicKey format from a byte[] is the following:

byte _key[];

RSAPublicKey rsaKey;

KeyFactory kfac = KeyFactory.getInstance("RSA");

BigInteger modulus = new BigInteger(_key);

RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);

rsaKey = (RSAPublicKey)kfac.generatePublic(kspec1);

The RSAPublicKey is scrambled with the code from your previous post! I tried reversing the steps and it seem to unscramble correctly but when i try to encrypt i get an exception:

javax.crypto.BadPaddingException: Message is larger than modulus

at sun.security.rsa.RSACore.parseMsg(RSACore.java:165)

at sun.security.rsa.RSACore.crypt(RSACore.java:95)

at sun.security.rsa.RSACore.rsa(RSACore.java:74)

at com.sun.crypto.provider.RSACipher.a(DashoA13*..)

at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)

at javax.crypto.Cipher.doFinal(DashoA13*..)

at walker.RequestAuth.<init>(RequestAuth.java:24)

at walker.LoginThread.run(LoginThread.java:52)

The message before encryption goes thru a padding function so the size it's always a multiple of 8. In this case the message size is 16 and the RSA modulus read from a network stream is 128 bytes.

Code used to encrypt the data[] is:

Cipher rsaCipher = Cipher.getInstance("RSA/ECB/nopadding");

rsaCipher.init(Cipher.ENCRYPT_MODE, _key);

data = rsaCipher.doFinal(data);

Any help would be appreciated!

Message was edited by:

pSal

pSala at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 4

I found what is the problem that generate the exception. But it generates another problem!

I read 128 bytes from the stream which represents the modulus of the RSAPublicKey, i pass it thru the unscrambler and then i make the public key! When i use System.out.println( _key.getModulus().signum())

i get sometimes a negative BigInteger and when encrypting i get the exception from previous post!

Using new BigInteger(byte array).abs()

i don't get the exception anymore but it alters the key and thus making it unuseable with it's pair!

pSala at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 5

I figured it out! When the server scrambles the key if it has 129 length and first byte is 0 then it strips the first byte and scrambles the next 128 bytes! So if u use only the 128 bytes sometimes you get a negative modulus, fix for this is to add a 0x00 before the rest!

This is the correct unscrambler code:

public class UnscrambledKeyPair {

public RSAPublicKey rsaKey;

public byte[] unscrambledModulus;

public UnscrambledKeyPair(RSAPublicKey rsa) {

this.rsaKey=rsa;

unscrambledModulus=unscrambleModulus(rsa.getModulus().toByteArray());

}

public static byte[] unscrambleModulus(byte[] unscrambledMod){

for (int i = 0; i < 0x40; i++){

unscrambledMod[0x40 + i] = (byte) (unscrambledMod[0x40 + i] ^ unscrambledMod[i]);

}

for (int i = 0; i < 4; i++){

unscrambledMod[0x0d + i] = (byte) (unscrambledMod[0x0d + i] ^ unscrambledMod[0x34 + i]);

}

for (int i = 0; i < 0x40; i++){

unscrambledMod[i] = (byte) (unscrambledMod[i] ^ unscrambledMod[0x40 + i]);

}

for (int i = 0; i < 4; i++){

byte temp = unscrambledMod[0x00 + i];

unscrambledMod[0x00 + i] = unscrambledMod[0x4d + i];

unscrambledMod[0x4d + i] = temp;

}

if (new BigInteger(unscrambledMod).signum()==-1)

{

byte[] temp = new byte[0x81];

System.arraycopy(unscrambledMod, 0, temp, 1, 0x80);

temp[0]=0x00;

unscrambledMod = temp;

}

return unscrambledMod;

}

}

Now it encrypts correctly!

pSala at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 6

Check out this Javadoc for one of the BigInteger constructors -

public BigInteger(int signum,

byte[] magnitude)

Translates the sign-magnitude representation of a BigInteger into a BigInteger. The sign is represented as an integer signum value: -1 for negative, 0 for zero, or 1 for positive. The magnitude is a byte array in big-endian byte-order: the most significant byte is in the zeroth element. A zero-length magnitude array is permissible, and will result inin a BigInteger value of 0, whether signum is -1, 0 or 1.

Parameters:

signum - signum of the number (-1 for negative, 0 for zero, 1 for positive).

magnitude - big-endian binary representation of the magnitude of the number.

sabre150a at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...
# 7

Thanks a lot! It's working perfectly!

Make the following changes to the code in my previous post!

/*if (new BigInteger(unscrambledMod).signum()==-1)

{

byte[] temp = new byte[0x81];

System.arraycopy(unscrambledMod, 0, temp, 1, 0x80);

temp[0]=0x00;

unscrambledMod = temp;

}*/

return new BigInteger(1,unscrambledMod).toByteArray();

Now it looks thinner! :)

pSala at 2007-7-11 15:33:16 > top of Java-index,Security,Cryptography...