Wrox Programmer Forums
Go Back   Wrox Programmer Forums > Java > Other Java > BOOK: Beginning Cryptography with Java
|
BOOK: Beginning Cryptography with Java
This is the forum to discuss the Wrox book Beginning Cryptography with Java by David Hook; ISBN: 9780764596339
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Beginning Cryptography with Java section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old April 25th, 2012, 11:50 AM
Registered User
 
Join Date: Apr 2012
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default Windows and Mac not giving the same results

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.
 
Old May 3rd, 2012, 12:19 PM
Registered User
 
Join Date: Apr 2012
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

SecureRandom is the source of the problem. On windows machines it produces random numbers using SHA1PRNG which given a particular seed will always generate the same number sequence, but on a mac it uses NativePRNG which does not behave the same way. So using SecureRandom.getInstance("SHA1PRNG") will solve the lack of matching results.

The problem I now face is that the only way I can see to set the algorythm being used is to do so using SecureRandom.getInstance("SHA1PRNG") but then how would the message digest stuff work (since it relies on extending SecureRandom). I'm back to reviewing the book because I don't really remember how the message digest stuff worked, the cryptography stuff blows my mind.
 
Old May 3rd, 2012, 06:55 PM
dgh dgh is offline
Wrox Author
 
Join Date: Aug 2005
Posts: 206
Thanks: 0
Thanked 20 Times in 20 Posts
Default

Sorry I missed your earlier post.

Yes, relying on deterministic behaviour of the RNG is a big mistake. It shouldn't make any difference what random numbers are involved in the key generation though, if it does there is something wrong with the approach been used to encrypt.

Regards,

David
 
Old May 7th, 2012, 04:40 PM
Registered User
 
Join Date: Apr 2012
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

OK, your post kind of blew my mind and made me realize I was doing something stupid... I uh... probably quit reading the book a little too soon, anyway, I did some digging and figured out what it seems I needed to know and now things are working well. (The solution was to save the keys to disk and distribute the keys for use on each computer that was decrypting the data).





Similar Threads
Thread Thread Starter Forum Replies Last Post
Final Qt SDK 1.1 now available for MS Windows, Apple Mac OS X, and Linux. tinachan Linux 0 May 23rd, 2011 02:59 AM
SQL count query not giving correct results hman SQL Language 2 March 16th, 2005 07:06 AM
SQL count query not giving correct results hman SQL Server 2000 1 March 15th, 2005 01:15 PM
Connect from Mac OS to Windows yarith Forum and Wrox.com Feedback 1 June 4th, 2003 08:45 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.