Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
 package org.jboss.crypto;
 
 
 
 import  org.jboss.logging.Logger;
 import  org.jboss.security.ErrorCodes;

Various security related utilities like MessageDigest factories, SecureRandom access, password hashing. This product includes software developed by Tom Wu and Eugene Jhong for the SRP Distribution (http://srp.stanford.edu/srp/).

Author(s):
Scott.Stark@jboss.org
Version:
$Revision: 62650 $
 
 public class CryptoUtil
 {
    private static Logger log = Logger.getLogger(CryptoUtil.class);
    private static final int HASH_LEN = 20;
    public static final String BASE64_ENCODING = "BASE64";
    public static final String BASE16_ENCODING = "HEX";
    public static final String RFC2617_ENCODING = "RFC2617";
   
The ASCII printable characters the MD5 digest maps to for RFC2617
 
    private static char[] MD5_HEX = "0123456789abcdef".toCharArray();
 
    private static SecureRandom psuedoRng;
    private static MessageDigest sha1Digest;
    private static boolean initialized;
 
    public static void init() throws NoSuchAlgorithmException
    {
       if )
          return;
       init(null);
    }
    public static void init(byte[] prngSeedthrows NoSuchAlgorithmException
    {
       // Get an instance of the SHA-1 digest
        = MessageDigest.getInstance("SHA");
       // Get a cryptographically strong pseudo-random generator
        = SecureRandom.getInstance("SHA1PRNG");
       ifprngSeed != null )
          .setSeed(prngSeed);
       // Install the JBossSX security provider
       Provider provider = new JBossSXProvider();
       Security.addProvider(provider);
        = true;
    }
 
    public static MessageDigest newDigest()
    {
       MessageDigest md = null;
       try
       {
          md = (MessageDigest.clone();
       }
       catch(CloneNotSupportedException e)
      {
      }
      return md;
   }
   public static MessageDigest copy(MessageDigest md)
   {
      MessageDigest copy = null;
      try
      {
         copy = (MessageDigestmd.clone();
      }
      catch(CloneNotSupportedException e)
      {
      }
      return copy;
   }
   public static Random getPRNG()
   {
      return ;
   }
   
Returns the next pseudorandom, uniformly distributed double value between 0.0 and 1.0 from this random number generator's sequence.
   public static double nextDouble()
   {
      return .nextDouble();
   }
   
Returns the next pseudorandom, uniformly distributed long value from this random number generator's sequence. The general contract of nextLong is that one long value is pseudorandomly generated and returned. All 264 possible long values are produced with (approximately) equal probability.
   public static long nextLong()
   {
      return .nextLong();
   }
   
Generates random bytes and places them into a user-supplied byte array. The number of random bytes produced is equal to the length of the byte array.
   public static void nextBytes(byte[] bytes)
   {
      .nextBytes(bytes);
   }
   
Returns the given number of seed bytes, computed using the seed generation algorithm that this class uses to seed itself. This call may be used to seed other random number generators.
   public static byte[] generateSeed(int numBytes)
   {
      return .generateSeed(numBytes);
   }

   
Cacluate the SRP RFC2945 password hash = H(salt | H(username | ':' | password)) where H = SHA secure hash. The username is converted to a byte[] using the UTF-8 encoding.
   public static byte[] calculatePasswordHash(String usernamechar[] password,
      byte[] salt)
   {
      // Calculate x = H(s | H(U | ':' | password))
      MessageDigest xd = newDigest();
      // Try to convert the username to a byte[] using UTF-8
      byte[] user = null;
      byte[] colon = {};
      try
      {
         user = username.getBytes("UTF-8");
         colon = ":".getBytes("UTF-8");
      }
      catch(UnsupportedEncodingException e)
      {
         .error("Failed to convert username to byte[] using UTF-8"e);
         // Use the default platform encoding
         user = username.getBytes();
         colon = ":".getBytes();
      }
      byte[] passBytes = new byte[2*password.length];
      int passBytesLength = 0;
      for(int p = 0; p < password.lengthp ++)
      {
         int c = (password[p] & 0x00FFFF);
         // The low byte of the char
         byte b0 = (byte) (c & 0x0000FF);
         // The high byte of the char
         byte b1 = (byte) ((c & 0x00FF00) >> 8);
         passBytes[passBytesLength ++] = b0;
         // Only encode the high byte if c is a multi-byte char
         ifc > 255 )
            passBytes[passBytesLength ++] = b1;
      }
      // Build the hash
      xd.update(user);
      xd.update(colon);
      xd.update(passBytes, 0, passBytesLength);
      byte[] h = xd.digest();
      xd.reset();
      xd.update(salt);
      xd.update(h);
      byte[] xb = xd.digest();
      return xb;
   }

   
Calculate x = H(s | H(U | ':' | password)) verifier v = g^x % N described in RFC2945.
   public static byte[] calculateVerifier(String usernamechar[] password,
      byte[] saltbyte[] Nbbyte[] gb)
   {
      BigInteger g = new BigInteger(1, gb);
      BigInteger N = new BigInteger(1, Nb);
      return calculateVerifier(usernamepasswordsaltNg);
   }
   
Calculate x = H(s | H(U | ':' | password)) verifier v = g^x % N described in RFC2945.
   public static byte[] calculateVerifier(String usernamechar[] password,
      byte[] saltBigInteger NBigInteger g)
   {
      byte[] xb = calculatePasswordHash(usernamepasswordsalt);
      BigInteger x = new BigInteger(1, xb);
      BigInteger v = g.modPow(xN);
      return v.toByteArray();
   }

   
Perform an interleaved even-odd hash on the byte string
   public static byte[] sessionKeyHash(byte[] number)
   {
      int ioffset;
      for(offset = 0; offset < number.length && number[offset] == 0; ++offset)
         ;
      byte[] key = new byte[2 * ];
      byte[] hout;
      int klen = (number.length - offset) / 2;
      byte[] hbuf = new byte[klen];
      for(i = 0; i < klen; ++i)
      {
         hbuf[i] = number[number.length - 2 * i - 1];
      }
      hout = newDigest().digest(hbuf);
      for(i = 0; i < ; ++i)
         key[2 * i] = hout[i];
      for(i = 0; i < klen; ++i)
      {
         hbuf[i] = number[number.length - 2 * i - 2];
      }
      hout = newDigest().digest(hbuf);
      for(i = 0; i < ; ++i)
         key[2 * i + 1] = hout[i];
      return key;
   }

   
Treat the input as the MSB representation of a number, and lop off leading zero elements. For efficiency, the input is simply returned if no leading zeroes are found.
   public static byte[] trim(byte[] in)
   {
      if(in.length == 0 || in[0] != 0)
         return in;
      int len = in.length;
      int i = 1;
      while(in[i] == 0 && i < len)
         ++i;
      byte[] ret = new byte[len - i];
      System.arraycopy(iniret, 0, len - i);
      return ret;
   }
   public static byte[] xor(byte[] b1byte[] b2int length)
   {
      byte[] result = new byte[length];
      for(int i = 0; i < length; ++i)
         result[i] = (byte) (b1[i] ^ b2[i]);
      return result;
   }

   
3.1.3 Representation of digest values An optional header allows the server to specify the algorithm used to create the checksum or digest. By default the MD5 algorithm is used and that is the only algorithm described in this document. For the purposes of this document, an MD5 digest of 128 bits is represented as 32 ASCII printable characters. The bits in the 128 bit digest are converted from most significant to least significant bit, four bits at a time to their ASCII presentation as follows. Each four bits is represented by its familiar hexadecimal notation from the characters 0123456789abcdef. That is, binary 0000 getInfos represented by the character '0', 0001, by '1', and so on up to the representation of 1111 as 'f'.

Parameters:
data - the raw MD5 hash data
Returns:
the encoded MD5 representation
   public static String encodeRFC2617(byte[] data)
   {
      char[] hash = new char[32];
      for (int i = 0; i < 16; i++)
      {
         int j = (data[i] >> 4) & 0xf;
         hash[i * 2] = [j];
         j = data[i] & 0xf;
         hash[i * 2 + 1] = [j];
      }
      return new String(hash);
   }

   
Hex encoding of hashes, as used by Catalina. Each byte is converted to the corresponding two hex characters.
   public static String encodeBase16(byte[] bytes)
   {
      StringBuffer sb = new StringBuffer(bytes.length * 2);
      for (int i = 0; i < bytes.lengthi++)
      {
         byte b = bytes[i];
         // top 4 bits
         char c = (char)((b >> 4) & 0xf);
         if(c > 9)
            c = (char)((c - 10) + 'a');
         else
            c = (char)(c + '0');
         sb.append(c);
         // bottom 4 bits
         c = (char)(b & 0xf);
         if (c > 9)
            c = (char)((c - 10) + 'a');
         else
            c = (char)(c + '0');
         sb.append(c);
      }
      return sb.toString();
   }

   
BASE64 encoder implementation. Provides encoding methods, using the BASE64 encoding rules, as defined in the MIME specification, rfc1521.
   public static String encodeBase64(byte[] bytes)
   {
      String base64 = null;
      try
      {
         base64 = Base64Encoder.encode(bytes);
      }
      catch(Exception e)
      {
      }
      return base64;
   }

  
Calculate a password hash using a MessageDigest.

Parameters:
hashAlgorithm - the MessageDigest algorithm name
hashEncoding - either base64 or hex to specify the type of encoding the MessageDigest as a string.
hashCharset - the charset used to create the byte[] passed to the MessageDigestfrom the password String. If null the platform default is used.
username - ignored in default version
password - the password string to be hashed
Returns:
the hashed string if successful, null if there is a digest exception
   public static String createPasswordHash(String hashAlgorithmString hashEncoding,
      String hashCharsetString usernameString password)
  {
     return createPasswordHash(hashAlgorithmhashEncoding,
      hashCharsetusernamepasswordnull);
  }
   
Calculate a password hash using a MessageDigest.

Parameters:
hashAlgorithm - the MessageDigest algorithm name
hashEncoding - either base64 or hex to specify the type of encoding the MessageDigest as a string.
hashCharset - the charset used to create the byte[] passed to the MessageDigestfrom the password String. If null the platform default is used.
username - ignored in default version
password - the password string to be hashed
callback - the callback used to allow customization of the hash to occur. The preDigest method is called before the password is added and the postDigest method is called after the password has been added.
Returns:
the hashed string if successful, null if there is a digest exception
 
   public static String createPasswordHash(String hashAlgorithmString hashEncoding,
      String hashCharsetString usernameString passwordDigestCallback callback)
   {
      byte[] passBytes;
      String passwordHash = null;
      // convert password to byte data
      try
      {
         if(hashCharset == null)
            passBytes = password.getBytes();
         else
            passBytes = password.getBytes(hashCharset);
      }
      catch(UnsupportedEncodingException uee)
      {
         .error("charset " + hashCharset + " not found. Using platform default."uee);
         passBytes = password.getBytes();
      }
      // calculate the hash and apply the encoding.
      try
      {
         MessageDigest md = MessageDigest.getInstance(hashAlgorithm);
         ifcallback != null )
            callback.preDigest(md);
         md.update(passBytes);
         ifcallback != null )
            callback.postDigest(md);
         byte[] hash = md.digest();
         if(hashEncoding.equalsIgnoreCase())
         {
            passwordHash =  encodeBase64(hash);
         }
         else if(hashEncoding.equalsIgnoreCase())
         {
            passwordHash =  encodeBase16(hash);
         }
         else if(hashEncoding.equalsIgnoreCase())
         {
            passwordHash =  encodeRFC2617(hash);
         }
         else
         {
            .error("Unsupported hash encoding format " + hashEncoding);
         }
      }
      catch(Exception e)
      {
         .error("Password hash calculation failed "e);
      }
      return passwordHash;
   }
   // These functions assume that the byte array has MSB at 0, LSB at end.
   // Reverse the byte array (not the String) if this is not the case.
   // All base64 strings are in natural order, least significant digit last.
   public static String tob64(byte[] buffer)
   {
      return Base64Utils.tob64(buffer);
   }
   public static byte[] fromb64(String strthrows NumberFormatException
   {
      return Base64Utils.fromb64(str);
   }

   
From Appendix E of the JCE ref guide, the xaximum key size allowed by the "Strong" jurisdiction policy files allows a maximum Blowfish cipher size of 128 bits.

Returns:
true if a Blowfish key can be initialized with 256 bit size, false otherwise.
 
   public static boolean hasUnlimitedCrypto()
   {
      boolean hasUnlimitedCrypto = false;
      try
      { 
         Class<?> keyGenClass = KeyGenerator.class;
         Class<?>[] sig = {String.class};
         Object[] args = {"Blowfish"};
         Method kgenInstance = keyGenClass.getDeclaredMethod("getInstance"sig);
         Object kgen = kgenInstance.invoke(nullargs);
         Class<?>[] sig2 = {int.class};
         Object[] args2 = {Integer.valueOf(256)};
         Method init = keyGenClass.getDeclaredMethod("init"sig2);         
         init.invoke(kgenargs2);
         hasUnlimitedCrypto = true;
      }
      catch(Throwable e)
      {
         .debug("hasUnlimitedCrypto error"e);
      }
      return hasUnlimitedCrypto;
   }

   
Use reflection to create a javax.crypto.spec.SecretKeySpec to avoid an explicit reference to SecretKeySpec so that the JCE is not needed unless the SRP parameters indicate that encryption is needed.

Returns:
a javax.cyrpto.SecretKey
   public static Object createSecretKey(String cipherAlgorithmObject keythrows KeyException
   {
      Class<?>[] signature = {key.getClass(), String.class};
      Object[] args = {keycipherAlgorithm};
      Object secretKey = null;
      try
      { 
          Class<?> secretKeySpecClass = SecretKeySpec.class;  
          Constructor<?> ctor = secretKeySpecClass.getDeclaredConstructor(signature);
          secretKey = ctor.newInstance(args);
      }
      catch(Exception e)
      {
          throw new KeyException(ErrorCodes.FAILED_TO_CREATE_SECRET_KEY_SPEC + e.getMessage());
      }
      catch(Throwable e)
      {
         throw new KeyException(ErrorCodes.UNEXPECTED_EXCEPTION_CREATE_SECRET_KEY_SPEC + e.getMessage());
      }
      return secretKey;
   }

   

Parameters:
cipherAlgorithm
Returns:
A javax.crypto.Cipher
Throws:
GeneralSecurityException
 
   public static Object createCipher(String cipherAlgorithm)
      throws GeneralSecurityException
   {
      javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm);
      return cipher;
   }
   public static Object createSealedObject(String cipherAlgorithmObject keybyte[] cipherIV,
      Serializable data)
      throws GeneralSecurityException
   {
      Object sealedObject = null;
      try
      {
          javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm);
         javax.crypto.SecretKey skey = (javax.crypto.SecretKeykey;
         ifcipherIV != null )
         {
            javax.crypto.spec.IvParameterSpec iv = new javax.crypto.spec.IvParameterSpec(cipherIV);
            cipher.init(...skeyiv);
         }
         else
         {
            cipher.init(...skey);
         }
         sealedObject = new javax.crypto.SealedObject(datacipher);
      }
      catch(GeneralSecurityException e)
      {
          throw e;
      }
      catch(Throwable e)
      {
         throw new GeneralSecurityException(ErrorCodes.FAILED_TO_CREATE_SEALEDOBJECT + e.getMessage());
      }
      return sealedObject;
   }
   public static Object accessSealedObject(String cipherAlgorithmObject keybyte[] cipherIV,
      Object obj)
      throws GeneralSecurityException
   {
      Object data = null;
      try
      {
          javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(cipherAlgorithm);
         javax.crypto.SecretKey skey = (javax.crypto.SecretKeykey;
         ifcipherIV != null )
         {
            javax.crypto.spec.IvParameterSpec iv = new javax.crypto.spec.IvParameterSpec(cipherIV);
            cipher.init(...skeyiv);
         }
         else
         {
            cipher.init(...skey);
         }
         javax.crypto.SealedObject sealedObj = (javax.crypto.SealedObjectobj;
         data = sealedObj.getObject(cipher);
      }
      catch(GeneralSecurityException e)
      {
          throw e;
      }
      catch(Throwable e)
      {
         throw new GeneralSecurityException(ErrorCodes.FAILED_TO_CREATE_SEALEDOBJECT + e.getMessage());
      }
      return data;
   }
   
New to GrepCode? Check out our FAQ X