I'm having trouble with some code which is probably ripped almost straight from the book (at least the encryption parts), and it has worked fine for some time, until I ran it on an OSX computer, I'd get an exception trying to decode (javax.crypto.BadPaddingException: unknown block type). That was when I was handling a file encrypted on a windows machine and decrypting it on an osx machine. I setup a test where I'd encrypt something simple and print the results, and then decrypt it and I got completely different results in both cases.
Here is a bit of code that reproduces this.
Code:
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.gg.GGUtils;
public class Test {
private static String digits = "0123456789abcdef";
private static KeyPair pair = null;
private static Key pubKey = null;
private static Key privKey = null;
private static Cipher cipher = null;
private static SecureRandom secrandom = null;
private static KeyPairGenerator generator = null;
public static void main(String[] arg) {
Security.addProvider(new BouncyCastleProvider());
ByteBuffer bb = ByteBuffer.allocate(10);
bb.putChar('b').putChar('e').putChar('e').putChar('f').putChar('.');
bb.flip();
bb = encrypt(bb);
decrypt(bb);
}
public static String toHex(byte[] data, int length)
{
StringBuffer buf = new StringBuffer();
for (int i = 0; i != length; i++)
{
int v = data[i] & 0xff;
buf.append(digits.charAt(v >> 4));
buf.append(digits.charAt(v & 0xf));
}
return buf.toString();
}
public static String toHex(byte[] data)
{
return toHex(data, data.length);
}
public static ByteBuffer stringToBuffer(String msg){
ByteBuffer bb = ByteBuffer.allocate(msg.length());
try {
bb.wrap(msg.getBytes("UTF-8"));
} catch (UnsupportedEncodingException uee) {
GGUtils.HandleException(uee);
}
return(bb);
}
public static String bufferToString(ByteBuffer buffer){
if (buffer != null) {
String s = null;
try {
s = new String(buffer.array(),"UTF-8");
} catch (UnsupportedEncodingException uee) {
GGUtils.HandleException(uee);
}
return(s);
} else {
return(null);
}
}
public static void initCipher() {
if (cipher != null) {
return;
}
try {
/*
key = new SecretKeySpec("abcdefghijklmnopqrstuvwx".getBytes(charset), "AES");
cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
*/
cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC");
secrandom = CCUtils.createFixedRandom();
// create the keys
generator = KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(2048, secrandom);
pair = generator.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate();
} catch (NoSuchAlgorithmException nsae) {
GGUtils.HandleException(nsae);
} catch (NoSuchProviderException nspe) {
GGUtils.HandleException(nspe);
} catch (NoSuchPaddingException nspae) {
GGUtils.HandleException(nspae);
}
}
public static ByteBuffer encrypt(ByteBuffer b) {
initCipher();
try {
String s = bufferToString(b);
byte[] input = s.getBytes("UTF-8");
System.out.println("input = "+GGUtils.toHex(input));
/*
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
*/
cipher.init(Cipher.ENCRYPT_MODE, pubKey, secrandom);
byte[] cipherText = cipher.doFinal(input);
//byte[] cipherText = input;
System.out.println("Here's our encrypt results");
System.out.println(GGUtils.toHex(cipherText));
b = ByteBuffer.wrap(cipherText);
// } catch (ShortBufferException sbe) {
// GGUtils.HandleException(sbe);
} catch (InvalidKeyException ike) {
GGUtils.HandleException(ike);
} catch (IllegalBlockSizeException ibse) {
GGUtils.HandleException(ibse);
} catch (BadPaddingException bpe) {
GGUtils.HandleException(bpe);
} catch (UnsupportedEncodingException uee) {
GGUtils.HandleException(uee);
}
return(b);
}
public static ByteBuffer decrypt(ByteBuffer b) {
initCipher();
//I can use the first or last X bytes as my salt
try {
byte[] cipherText = b.array();
/*
int ctLength = cipherText.length;
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
*/
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] plainText = cipher.doFinal(cipherText);
System.out.println("output = "+GGUtils.toHex(plainText));
b = ByteBuffer.wrap(plainText);
// } catch (ShortBufferException sbe) {
// GGUtils.HandleException(sbe);
} catch (InvalidKeyException ike) {
GGUtils.HandleException(ike);
} catch (IllegalBlockSizeException ibse) {
GGUtils.HandleException(ibse);
} catch (BadPaddingException bpe) {
GGUtils.HandleException(bpe);
}
return(b);
}
}
class CCUtils
{
private static class FixedRand extends SecureRandom
{
MessageDigest sha;
byte[] state;
FixedRand()
{
try
{
this.sha = MessageDigest.getInstance("SHA-1");
this.state = sha.digest();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("can't find SHA-1!");
}
}
public void nextBytes(
byte[] bytes)
{
int off = 0;
sha.update(state);
while (off < bytes.length)
{
state = sha.digest();
if (bytes.length - off > state.length)
{
System.arraycopy(state, 0, bytes, off, state.length);
}
else
{
System.arraycopy(state, 0, bytes, off, bytes.length - off);
}
off += state.length;
sha.update(state);
}
}
}
public static SecureRandom createFixedRandom()
{
return new FixedRand();
}
}
When run on a windows machine it produces this output.
Code:
input = 0062006500650066002e
Here's our encrypt results
13cafa65e48f0b48a4d60d0a168118ce7ae31f12953e3eae508ff09c93facb306f26fb3bd83c6f9b21cc85bf7a84e355a512ce496e40492f4c7212430c7477d10bb4871d0dd99658d913f01cae200313b298963d47215698a40a7ca4741e4fb9acea64f63ac636993b42b7afe6b9fe9c5af005b8683cf1a480e2c4ac17ccee0f8892682fdc64de4168eccf52af5a90b76c9625234a7edc254dce990fbcc18b448d1b067765f0da7c54e5619c35833fb43b22733d164ebdcc5a17187c02992a4d535b1d661ef941ba3baef39c73bcbefae39f950031413e8ddd711755e4551857f0896e93123e325f89000b702b4cbec3921f7f1c7600489e577ef1cf7a3f27f7
output = 0062006500650066002e
When run on a mac osx machine, it products the following output.
Code:
input = 0062006500650066002e
Here's our encrypt results
16567866d7ecf5702716bc27c1635aeda6f115540596bab2f09f10f6de8a47c445df30ee6f7b4f8461dd59bfabd13e48d26bad1458daade15919bb982c33af86d9ba26e5839503eeed618dbfe183fd21a5fbdd489555978d64c97fff2de0529791b9dcfac6bed0530a10af484a2ebaaa500699d514c6e23e83fd0b160d57d7914bb519fa748ba42ceaa7378eee41153c669fba990d460a91eeaab6c578e6f3ca270723f2e1f13a77fbe961547df22bde39137418d6094e367db07a27ace53ea32633e4118744732653870343b11eb242e51547fa79070ab6efec82215cafbfc808d8ae29718af8e1d04c524f2a8811ecfda408eaf0b89ca7d7cd282b6b12f71a
output = 0062006500650066002e
This is using the Bouncy Castle 1.47 (compiled for JDK 1.4). I thought maybe different numbers were being generated by the SecureRandom but that didn't seem to be the case... though I only checked the first result, perhaps a floating point error exists between the two. I also can't really rule out that this is a bug in bouncy castle and not related to the code itself.