1 4 5 package com.sun.j2ee.blueprints.clientstate; 6 7 import java.io.ByteArrayInputStream ; 8 import java.security.Key ; 9 import java.security.MessageDigest ; 10 import java.security.SecureRandom ; 11 import java.util.Arrays ; 12 import javax.crypto.Cipher; 13 import javax.crypto.Mac; 14 import javax.crypto.SecretKeyFactory; 15 import javax.crypto.spec.DESedeKeySpec; 16 import javax.crypto.spec.IvParameterSpec; 17 import javax.crypto.spec.SecretKeySpec; 18 19 20 21 28 public class ByteArrayGuard { 29 public static final int DEFAULT_KEY_LENGTH = 24; 30 public static final int DEFAULT_MAC_LENGTH = 20; 31 public static final int DEFAULT_IV_LENGTH = 8; 32 33 40 public ByteArrayGuard(PasswordStrategy ps) { 41 this(ps, DEFAULT_KEY_LENGTH, DEFAULT_MAC_LENGTH, DEFAULT_IV_LENGTH); 42 } 43 44 51 public ByteArrayGuard(PasswordStrategy ps, int keyLength, int macLength, int ivLength) { 52 this.passwordStrategy = ps; 53 this.keyLength = keyLength; 54 this.macLength = macLength; 55 this.ivLength = ivLength; 56 if (ps == null) { 57 System.err.println("The password strategy to encrypt the client-side state is specified null. " 62 + "We will set it to a default value. This will enable the encryption and decryption to work, but the client-side state is NO longer secure."); 63 password = "easy-to-guess-password"; 64 } 65 } 66 67 75 public byte[] encrypt(byte[] plaindata) { 76 try { 77 byte[] rawKey = convertPasswordToKey(getPasswordToSecureState()); 79 Cipher cipher = getBlockCipherForEncryption(rawKey); 81 byte[] encdata = cipher.doFinal(plaindata); 83 Mac mac = getMac(rawKey); 85 byte[] iv = cipher.getIV(); 87 mac.update(iv); 88 mac.update(encdata); 90 byte[] macBytes = mac.doFinal(); 92 95 byte[] tmp = concatBytes(macBytes, iv); 100 byte[] securedata = concatBytes(tmp, encdata); 101 return securedata; 102 } catch (Exception e) { 103 throw new RuntimeException (e); 104 } 105 } 106 107 115 public byte[] decrypt(byte[] securedata) { 116 try { 117 byte[] macBytes = new byte[macLength]; 119 System.arraycopy(securedata, 0, macBytes, 0, macBytes.length); 120 byte[] iv = new byte[ivLength]; 122 System.arraycopy(securedata, macBytes.length, iv, 0, iv.length); 123 126 byte[] encdata = new byte[securedata.length - macBytes.length - iv.length]; 128 System.arraycopy(securedata, macBytes.length + iv.length, encdata, 0, encdata.length); 129 130 byte[] rawKey = convertPasswordToKey(getPasswordToSecureState()); 132 Mac mac = getMac(rawKey); 133 mac.update(iv); 134 mac.update(encdata); 135 byte[] macBytesCalculated = mac.doFinal(); 136 if (Arrays.equals(macBytes, macBytesCalculated)) { 137 Cipher cipher = getBlockCipherForDecryption(rawKey, iv); 140 byte[] plaindata = cipher.doFinal(encdata); 141 return plaindata; 142 } else { 143 System.err.println("ERROR: MAC did not verify!"); 144 return null; 145 } 146 } catch (Exception e) { 147 return null; 148 } 149 } 150 151 153 private String getPasswordToSecureState() { 154 if (password == null) { 155 password = passwordStrategy.getPassword(); 156 } 157 return password; 158 } 159 166 private byte[] convertPasswordToKey(byte[] password) { 167 try { 168 MessageDigest md = MessageDigest.getInstance("SHA"); 169 byte[] seed = md.digest(password); 170 171 SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); 172 random.setSeed(seed); 173 174 byte[] rawkey = new byte[keyLength]; 175 random.nextBytes(rawkey); 176 return rawkey; 177 } catch (Exception e) { 178 throw new RuntimeException (e); 179 } 180 } 181 182 184 private byte[] convertPasswordToKey(String password) { 185 return convertPasswordToKey(password.getBytes()); 186 } 187 188 191 private Cipher getBlockCipherForEncryption(byte[] rawKey) { 192 try { 193 SecretKeyFactory keygen = SecretKeyFactory.getInstance("DESede"); 194 DESedeKeySpec keyspec = new DESedeKeySpec(rawKey); 195 Key key = keygen.generateSecret(keyspec); 196 Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 197 byte[] iv = new byte[ivLength]; 198 getPRNG().nextBytes(iv); 199 IvParameterSpec ivspec = new IvParameterSpec(iv); 200 cipher.init(Cipher.ENCRYPT_MODE, key, ivspec, getPRNG()); 201 return cipher; 202 } catch (Exception e) { 203 throw new RuntimeException (e); 204 } 205 } 206 207 private static Cipher getBlockCipherForDecryption(byte[] rawKey, byte[] 208 iv) { 209 try { 212 SecretKeyFactory keygen = SecretKeyFactory.getInstance("DESede"); 213 DESedeKeySpec keyspec = new DESedeKeySpec(rawKey); 214 Key key = keygen.generateSecret(keyspec); 215 Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 216 IvParameterSpec ivspec = new IvParameterSpec(iv); 217 cipher.init(Cipher.DECRYPT_MODE, key, ivspec, getPRNG()); 218 return cipher; 219 } catch (Exception e) { 220 throw new RuntimeException (e); 221 } 222 } 223 224 private Mac getMac(byte[] rawKey) { 225 try { 227 Mac mac = Mac.getInstance("HmacSHA1"); 228 SecretKeySpec key = new SecretKeySpec(rawKey, 0, macLength, "HmacSHA1"); 229 mac.init(key); 230 return mac; 231 } catch (Exception e) { 232 throw new RuntimeException (e); 233 } 234 } 235 236 240 static String getRandomString(int size) { 241 byte[] data = new byte[size]; 242 getPRNG().nextBytes(data); 243 return new String (data); 244 } 245 246 private static int getRandomInt() { 247 byte[] data = new byte[4]; 248 getPRNG().nextBytes(data); 249 return data[0] + data[1] * 256 + data[2] * 65536 + data[3] * 16777216; 250 } 251 252 private static SecureRandom getPRNG() { 253 try { 254 if (prng == null) { 255 prng = SecureRandom.getInstance("SHA1PRNG"); 256 } 257 return prng; 258 } catch (Exception e) { 259 throw new RuntimeException (e); 260 } 261 } 262 263 private static String getHexString(byte[] b) { 264 StringBuffer buf = new StringBuffer (b.length); 265 for (int i = 0; i < b.length; ++i) { 266 byte2hex(b[i], buf); 267 } 268 return buf.toString(); 269 } 270 271 277 private static byte[] concatBytes(byte[] array1, byte[] array2) { 278 byte[] cBytes = new byte[array1.length + array2.length]; 279 try { 280 System.arraycopy(array1, 0, cBytes, 0, array1.length); 281 System.arraycopy(array2, 0, cBytes, array1.length, array2.length); 282 } catch(Exception e) { 283 System.out.println("Exception <concatBytes> " + e ); 284 } 285 return cBytes; 286 } 287 288 291 private static void byte2hex(byte b, StringBuffer buf) { 292 char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8','9', 'A', 'B', 'C', 'D', 'E', 'F' }; 293 int high = ((b & 0xf0) >> 4); 294 int low = (b & 0x0f); 295 buf.append(hexChars[high]); 296 buf.append(hexChars[low]); 297 } 298 299 private int keyLength; 300 private int macLength; 301 private int ivLength; 302 private String password = null; 303 private PasswordStrategy passwordStrategy; 304 private static SecureRandom prng = null; 305 } 306 | Popular Tags |