1

I am not an expert in cryptography and I am getting some interesting results when I use the encryption method below.

The server is .NET C# and the client runs JAVA. Basically, We encrypt credit card information and for the 12 credit cards I have, 11 works perfectly with the methods below.

However, one of the cards (real VISA credit CARD) the result returned by encrypt() and converted to hex has a negative symbol in the start of the string, like this:

-6d9830a52b2c3add7a78fd9897bca19d....., it fails when the server tries to decrypt it and I think it should be positive not negative based on this explanation RSA - Encryption with negative exponent

            private static byte[] encrypt(String text, PublicKey pubRSA) throws Exception
            {
             Cipher cipher = Cipher.getInstance(RSA);
             cipher.init(Cipher.ENCRYPT_MODE, pubRSA);
             return cipher.doFinal(text.getBytes());
            }

            //Using this encryption method one card could not be decrypted by vPAY due to negative (exponential) symbol.
            //It may have the same affect with other cards
            public final static byte[] encrypt(String text)
            {
             try {

                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(Base64.decode(pkBase64));
                PublicKey pk = keyFactory.generatePublic(x509Spec);

                return encrypt(text, pk);
             }
             catch(Exception e)
             {
              e.printStackTrace();
             }
             return null;
            }

Has anyone faced something like that and found a workaround? I have tried three other algorithms with different KeySpec and the same publicKey (the source is a string in base64 format) but none of them could be decrypted by the server even with the cards the were working before...

UPDATE 1

This is how a convert the encrypted result in bytes to HEX:

            public static String byteToHex(byte[] string)
              {
                    try {
                        return String.format("%04x", new BigInteger(string));
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        return null;
                    }
              }
Community
  • 1
  • 1
Devester
  • 1,183
  • 4
  • 14
  • 41
  • How do you convert to hex? byte are signed is Java. You probably need to get the unsigned value in a int (http://stackoverflow.com/questions/4266756/can-we-make-unsigned-byte-in-java) before convert it to hex string. – Kazaag Aug 19 '13 at 09:55
  • @Kazaag thanks for attention on that....please see "UPDATE 1". – Devester Aug 19 '13 at 10:11

2 Answers2

3

You should print out the hexadecimal string directly from byte[]. This can be done using the following code:

StringBuilder sb = new StringBuilder(data.length * 2);
for (int i = 0; i < data.length; i++) {
    sb.append(String.format("%02X", data[i] & 0xFF));
}
return sb.toString();

There is no need to use BigInteger. In fact, it is dangerous to use BigInteger. One reason is the one you've already encountered: BigInteger conversion to/from byte[] is using signed big endian encoding by default. The other thing is that the output of the RSA signature (as integer) may be smaller than the modulus size in hexadecimals. This is why EJP's solution will fail now and then.

RSA output has been defined in bytes, as an unsigned big endian encoded in the same number of bits as the key size (using integer to octet string encoding in the standard documents).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
2

public static String byteToHex(byte[] string)

A byte[] is not a string. It's a byte array. Don't confuse yourself with inappropriate variable names. String is not a container for binary data.

return String.format("%04x", new BigInteger(string));

Try return new BigInteger(1,string).toString(16), and have a look at the Javadoc to see why this works where new BigInteger(string) didn't.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 2
    This does not always work. BigInteger output may be smaller than the output of RSA encryption. So you would be missing starting zero's. There is no need to convert to/from BigInteger either. – Maarten Bodewes Aug 19 '13 at 10:34