1 7 package org.jboss.security; 8 9 import java.io.Serializable ; 10 import java.io.UnsupportedEncodingException ; 11 import java.lang.reflect.Constructor ; 12 import java.lang.reflect.Method ; 13 import java.math.BigInteger ; 14 import java.security.GeneralSecurityException ; 15 import java.security.KeyException ; 16 import java.security.MessageDigest ; 17 import java.security.NoSuchAlgorithmException ; 18 import java.security.Provider ; 19 import java.security.Security ; 20 import java.security.SecureRandom ; 21 import java.util.Random ; 22 23 import org.jboss.crypto.JBossSXProvider; 24 import org.jboss.crypto.digest.DigestCallback; 25 import org.jboss.logging.Logger; 26 27 36 public class Util 37 { 38 private static Logger log = Logger.getLogger(Util.class); 39 private static final int HASH_LEN = 20; 40 public static final String BASE64_ENCODING = "BASE64"; 41 public static final String BASE16_ENCODING = "HEX"; 42 43 private static SecureRandom psuedoRng; 44 private static MessageDigest sha1Digest; 45 private static boolean initialized; 46 47 public static void init() throws NoSuchAlgorithmException 48 { 49 if( initialized ) 50 return; 51 init(null); 52 } 53 public static void init(byte[] prngSeed) throws NoSuchAlgorithmException 54 { 55 sha1Digest = MessageDigest.getInstance("SHA"); 57 psuedoRng = SecureRandom.getInstance("SHA1PRNG"); 59 if( prngSeed != null ) 60 psuedoRng.setSeed(prngSeed); 61 Provider provider = new JBossSXProvider(); 63 Security.addProvider(provider); 64 initialized = true; 65 } 66 67 public static MessageDigest newDigest() 68 { 69 MessageDigest md = null; 70 try 71 { 72 md = (MessageDigest ) sha1Digest.clone(); 73 } 74 catch(CloneNotSupportedException e) 75 { 76 } 77 return md; 78 } 79 public static MessageDigest copy(MessageDigest md) 80 { 81 MessageDigest copy = null; 82 try 83 { 84 copy = (MessageDigest ) md.clone(); 85 } 86 catch(CloneNotSupportedException e) 87 { 88 } 89 return copy; 90 } 91 92 public static Random getPRNG() 93 { 94 return psuedoRng; 95 } 96 99 public static double nextDouble() 100 { 101 return psuedoRng.nextDouble(); 102 } 103 109 public static long nextLong() 110 { 111 return psuedoRng.nextLong(); 112 } 113 117 public static void nextBytes(byte[] bytes) 118 { 119 psuedoRng.nextBytes(bytes); 120 } 121 125 public static byte[] generateSeed(int numBytes) 126 { 127 return psuedoRng.generateSeed(numBytes); 128 } 129 130 134 public static byte[] calculatePasswordHash(String username, char[] password, 135 byte[] salt) 136 { 137 MessageDigest xd = newDigest(); 139 byte[] user = null; 141 byte[] colon = {}; 142 try 143 { 144 user = username.getBytes("UTF-8"); 145 colon = ":".getBytes("UTF-8"); 146 } 147 catch(UnsupportedEncodingException e) 148 { 149 log.error("Failed to convert username to byte[] using UTF-8", e); 150 user = username.getBytes(); 152 colon = ":".getBytes(); 153 } 154 byte[] passBytes = new byte[2*password.length]; 155 int passBytesLength = 0; 156 for(int p = 0; p < password.length; p ++) 157 { 158 int c = (password[p] & 0x00FFFF); 159 byte b0 = (byte) (c & 0x0000FF); 161 byte b1 = (byte) ((c & 0x00FF00) >> 8); 163 passBytes[passBytesLength ++] = b0; 164 if( c > 255 ) 166 passBytes[passBytesLength ++] = b1; 167 } 168 169 xd.update(user); 171 xd.update(colon); 172 xd.update(passBytes, 0, passBytesLength); 173 byte[] h = xd.digest(); 174 xd.reset(); 175 xd.update(salt); 176 xd.update(h); 177 byte[] xb = xd.digest(); 178 return xb; 179 } 180 181 185 public static byte[] calculateVerifier(String username, char[] password, 186 byte[] salt, byte[] Nb, byte[] gb) 187 { 188 BigInteger g = new BigInteger (1, gb); 189 BigInteger N = new BigInteger (1, Nb); 190 return calculateVerifier(username, password, salt, N, g); 191 } 192 196 public static byte[] calculateVerifier(String username, char[] password, 197 byte[] salt, BigInteger N, BigInteger g) 198 { 199 byte[] xb = calculatePasswordHash(username, password, salt); 200 BigInteger x = new BigInteger (1, xb); 201 BigInteger v = g.modPow(x, N); 202 return v.toByteArray(); 203 } 204 205 207 public static byte[] sessionKeyHash(byte[] number) 208 { 209 int i, offset; 210 211 for(offset = 0; offset < number.length && number[offset] == 0; ++offset) 212 ; 213 214 byte[] key = new byte[2 * HASH_LEN]; 215 byte[] hout; 216 217 int klen = (number.length - offset) / 2; 218 byte[] hbuf = new byte[klen]; 219 220 for(i = 0; i < klen; ++i) 221 { 222 hbuf[i] = number[number.length - 2 * i - 1]; 223 } 224 hout = newDigest().digest(hbuf); 225 for(i = 0; i < HASH_LEN; ++i) 226 key[2 * i] = hout[i]; 227 228 for(i = 0; i < klen; ++i) 229 { 230 hbuf[i] = number[number.length - 2 * i - 2]; 231 } 232 hout = newDigest().digest(hbuf); 233 for(i = 0; i < HASH_LEN; ++i) 234 key[2 * i + 1] = hout[i]; 235 236 return key; 237 } 238 239 243 public static byte[] trim(byte[] in) 244 { 245 if(in.length == 0 || in[0] != 0) 246 return in; 247 248 int len = in.length; 249 int i = 1; 250 while(in[i] == 0 && i < len) 251 ++i; 252 byte[] ret = new byte[len - i]; 253 System.arraycopy(in, i, ret, 0, len - i); 254 return ret; 255 } 256 257 public static byte[] xor(byte[] b1, byte[] b2, int length) 258 { 259 byte[] result = new byte[length]; 260 for(int i = 0; i < length; ++i) 261 result[i] = (byte) (b1[i] ^ b2[i]); 262 return result; 263 } 264 265 269 public static String encodeBase16(byte[] bytes) 270 { 271 StringBuffer sb = new StringBuffer (bytes.length * 2); 272 for (int i = 0; i < bytes.length; i++) 273 { 274 byte b = bytes[i]; 275 char c = (char)((b >> 4) & 0xf); 277 if(c > 9) 278 c = (char)((c - 10) + 'a'); 279 else 280 c = (char)(c + '0'); 281 sb.append(c); 282 c = (char)(b & 0xf); 284 if (c > 9) 285 c = (char)((c - 10) + 'a'); 286 else 287 c = (char)(c + '0'); 288 sb.append(c); 289 } 290 return sb.toString(); 291 } 292 293 298 public static String encodeBase64(byte[] bytes) 299 { 300 String base64 = null; 301 try 302 { 303 base64 = Base64Encoder.encode(bytes); 304 } 305 catch(Exception e) 306 { 307 } 308 return base64; 309 } 310 311 324 public static String createPasswordHash(String hashAlgorithm, String hashEncoding, 325 String hashCharset, String username, String password) 326 { 327 return createPasswordHash(hashAlgorithm, hashEncoding, 328 hashCharset, username, password, null); 329 } 330 346 public static String createPasswordHash(String hashAlgorithm, String hashEncoding, 347 String hashCharset, String username, String password, DigestCallback callback) 348 { 349 byte[] passBytes; 350 String passwordHash = null; 351 352 try 354 { 355 if(hashCharset == null) 356 passBytes = password.getBytes(); 357 else 358 passBytes = password.getBytes(hashCharset); 359 } 360 catch(UnsupportedEncodingException uee) 361 { 362 log.error("charset " + hashCharset + " not found. Using platform default.", uee); 363 passBytes = password.getBytes(); 364 } 365 366 try 368 { 369 MessageDigest md = MessageDigest.getInstance(hashAlgorithm); 370 if( callback != null ) 371 callback.preDigest(md); 372 md.update(passBytes); 373 if( callback != null ) 374 callback.postDigest(md); 375 byte[] hash = md.digest(); 376 if(hashEncoding.equalsIgnoreCase(BASE64_ENCODING)) 377 { 378 passwordHash = Util.encodeBase64(hash); 379 } 380 else if(hashEncoding.equalsIgnoreCase(BASE16_ENCODING)) 381 { 382 passwordHash = Util.encodeBase16(hash); 383 } 384 else 385 { 386 log.error("Unsupported hash encoding format " + hashEncoding); 387 } 388 } 389 catch(Exception e) 390 { 391 log.error("Password hash calculation failed ", e); 392 } 393 return passwordHash; 394 } 395 396 public static String tob64(byte[] buffer) 400 { 401 return Base64Utils.tob64(buffer); 402 } 403 404 public static byte[] fromb64(String str) throws NumberFormatException 405 { 406 return Base64Utils.fromb64(str); 407 } 408 409 415 public static boolean hasUnlimitedCrypto() 416 { 417 boolean hasUnlimitedCrypto = false; 418 try 419 { 420 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 421 Class keyGenClass = loader.loadClass("javax.crypto.KeyGenerator"); 422 Class [] sig = {String .class}; 423 Object [] args = {"Blowfish"}; 424 Method kgenInstance = keyGenClass.getDeclaredMethod("getInstance", sig); 425 Object kgen = kgenInstance.invoke(null, args); 426 427 Class [] sig2 = {int.class}; 428 Object [] args2 = {new Integer (256)}; 429 Method init = keyGenClass.getDeclaredMethod("init", sig2); 430 init.invoke(kgen, args2); 431 hasUnlimitedCrypto = true; 432 } 433 catch(Throwable e) 434 { 435 log.debug("hasUnlimitedCrypto error", e); 436 } 437 return hasUnlimitedCrypto; 438 } 439 440 445 public static Object createSecretKey(String cipherAlgorithm, Object key) throws KeyException 446 { 447 Class [] signature = {key.getClass(), String .class}; 448 Object [] args = {key, cipherAlgorithm}; 449 Object secretKey = null; 450 try 451 { 452 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 453 Class secretKeySpecClass = loader.loadClass("javax.crypto.spec.SecretKeySpec"); 454 Constructor ctor = secretKeySpecClass.getDeclaredConstructor(signature); 455 secretKey = ctor.newInstance(args); 456 } 457 catch(Exception e) 458 { 459 throw new KeyException ("Failed to create SecretKeySpec from session key, msg="+e.getMessage()); 460 } 461 catch(Throwable e) 462 { 463 throw new KeyException ("Unexpected exception during SecretKeySpec creation, msg="+e.getMessage()); 464 } 465 return secretKey; 466 } 467 468 473 public static Object createCipher(String cipherAlgorithm) 474 throws GeneralSecurityException 475 { 476 javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm); 477 return cipher; 478 } 479 public static Object createSealedObject(String cipherAlgorithm, Object key, byte[] cipherIV, 480 Serializable data) 481 throws GeneralSecurityException 482 { 483 Object sealedObject = null; 484 try 485 { 486 javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm); 487 javax.crypto.SecretKey skey = (javax.crypto.SecretKey) key; 488 if( cipherIV != null ) 489 { 490 javax.crypto.spec.IvParameterSpec iv = new javax.crypto.spec.IvParameterSpec(cipherIV); 491 cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, skey, iv); 492 } 493 else 494 { 495 cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, skey); 496 } 497 sealedObject = new javax.crypto.SealedObject(data, cipher); 498 } 499 catch(GeneralSecurityException e) 500 { 501 throw e; 502 } 503 catch(Throwable e) 504 { 505 throw new GeneralSecurityException ("Failed to create SealedObject, msg="+e.getMessage()); 506 } 507 return sealedObject; 508 } 509 510 public static Object accessSealedObject(String cipherAlgorithm, Object key, byte[] cipherIV, 511 Object obj) 512 throws GeneralSecurityException 513 { 514 Object data = null; 515 try 516 { 517 javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm); 518 javax.crypto.SecretKey skey = (javax.crypto.SecretKey) key; 519 if( cipherIV != null ) 520 { 521 javax.crypto.spec.IvParameterSpec iv = new javax.crypto.spec.IvParameterSpec(cipherIV); 522 cipher.init(javax.crypto.Cipher.DECRYPT_MODE, skey, iv); 523 } 524 else 525 { 526 cipher.init(javax.crypto.Cipher.DECRYPT_MODE, skey); 527 } 528 javax.crypto.SealedObject sealedObj = (javax.crypto.SealedObject) obj; 529 data = sealedObj.getObject(cipher); 530 } 531 catch(GeneralSecurityException e) 532 { 533 throw e; 534 } 535 catch(Throwable e) 536 { 537 throw new GeneralSecurityException ("Failed to access SealedObject, msg="+e.getMessage()); 538 } 539 return data; 540 } 541 } 542 | Popular Tags |