[seam-commits] Seam SVN: r10419 - in trunk/src/main/org/jboss/seam/security: crypto and 1 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Apr 15 02:41:04 EDT 2009


Author: shane.bryzak at jboss.com
Date: 2009-04-15 02:41:04 -0400 (Wed, 15 Apr 2009)
New Revision: 10419

Added:
   trunk/src/main/org/jboss/seam/security/crypto/
   trunk/src/main/org/jboss/seam/security/crypto/BinTools.java
   trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java
   trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java
   trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
   trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java
   trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java
   trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java
   trunk/src/main/org/jboss/seam/security/crypto/PRF.java
Modified:
   trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
   trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
Log:
hashing algorithms in jdk5 suck, so provide our own default one

Added: trunk/src/main/org/jboss/seam/security/crypto/BinTools.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/BinTools.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/BinTools.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,122 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * Free auxiliary functions. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public class BinTools
+{
+   public static final String hex = "0123456789ABCDEF";
+   
+   /**
+    * Simple binary-to-hexadecimal conversion.
+    * 
+    * @param b
+    *           Input bytes. May be <code>null</code>.
+    * @return Hexadecimal representation of b. Uppercase A-F, two characters per
+    *         byte. Empty string on <code>null</code> input.
+    */
+   public static String bin2hex(final byte[] b)
+   {
+      if (b == null)
+      {
+         return "";
+      }
+      StringBuffer sb = new StringBuffer(2 * b.length);
+      for (int i = 0; i < b.length; i++)
+      {
+         int v = (256 + b[i]) % 256;
+         sb.append(hex.charAt((v / 16) & 15));
+         sb.append(hex.charAt((v % 16) & 15));
+      }
+      return sb.toString();
+   }
+   
+   /**
+    * Convert hex string to array of bytes.
+    * 
+    * @param s
+    *           String containing hexadecimal digits. May be <code>null</code>.
+    *           On odd length leading zero will be assumed.
+    * @return Array on bytes, non-<code>null</code>.
+    * @throws IllegalArgumentException
+    *            when string contains non-hex character
+    */
+   public static byte[] hex2bin(final String s)
+   {
+      String m = s;
+      if (s == null)
+      {
+         // Allow empty input string.
+         m = "";
+      }
+      else if (s.length() % 2 != 0)
+      {
+         // Assume leading zero for odd string length
+         m = "0" + s;
+      }
+      byte r[] = new byte[m.length() / 2];
+      for (int i = 0, n = 0; i < m.length(); n++)
+      {
+         char h = m.charAt(i++);
+         char l = m.charAt(i++);
+         r[n] = (byte) (hex2bin(h) * 16 + hex2bin(l));
+      }
+      return r;
+   }
+   
+   /**
+    * Convert hex digit to numerical value.
+    * 
+    * @param c
+    *           0-9, a-f, A-F allowd.
+    * @return 0-15
+    * @throws IllegalArgumentException
+    *            on non-hex character
+    */
+   public static int hex2bin(char c)
+   {
+      if (c >= '0' && c <= '9')
+      {
+         return (c - '0');
+      }
+      if (c >= 'A' && c <= 'F')
+      {
+         return (c - 'A' + 10);
+      }
+      if (c >= 'a' && c <= 'f')
+      {
+         return (c - 'a' + 10);
+      }
+      throw new IllegalArgumentException("Input string may only contain hex digits, but found '" + c + "'");
+   }
+}
\ No newline at end of file

Added: trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/MacBasedPRF.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,114 @@
+package org.jboss.seam.security.crypto;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * Default PRF implementation based on standard javax.crypt.Mac mechanisms.
+ * 
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public class MacBasedPRF implements PRF
+{
+    protected Mac mac;
+
+    protected int hLen;
+
+    protected String macAlgorithm;
+
+    /**
+     * Create Mac-based Pseudo Random Function.
+     * 
+     * @param macAlgorithm
+     *            Mac algorithm to use, i.e. HMacSHA1 or HMacMD5.
+     */
+    public MacBasedPRF(String macAlgorithm)
+    {
+        this.macAlgorithm = macAlgorithm;
+        try
+        {
+            mac = Mac.getInstance(macAlgorithm);
+            hLen = mac.getMacLength();
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public MacBasedPRF(String macAlgorithm, String provider)
+    {
+        this.macAlgorithm = macAlgorithm;
+        try
+        {
+            mac = Mac.getInstance(macAlgorithm, provider);
+            hLen = mac.getMacLength();
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new RuntimeException(e);
+        }
+        catch (NoSuchProviderException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public byte[] doFinal(byte[] M)
+    {
+        byte[] r = mac.doFinal(M);
+        return r;
+    }
+
+    public int getHLen()
+    {
+        return hLen;
+    }
+
+    public void init(byte[] P)
+    {
+        try
+        {
+            mac.init(new SecretKeySpec(P, macAlgorithm));
+        }
+        catch (InvalidKeyException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+}

Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,102 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html.
+ * 
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public interface PBKDF2
+{
+   /**
+    * Convert String-based input to internal byte array, then invoke PBKDF2.
+    * Desired key length defaults to Pseudo Random Function block size.
+    * 
+    * @param inputPassword
+    *           Candidate password to compute the derived key for.
+    * @return internal byte array
+    */
+   public abstract byte[] deriveKey(String inputPassword);
+   
+   /**
+    * Convert String-based input to internal byte array, then invoke PBKDF2.
+    * 
+    * @param inputPassword
+    *           Candidate password to compute the derived key for.
+    * @param dkLen
+    *           Specify desired key length
+    * @return internal byte array
+    */
+   public abstract byte[] deriveKey(String inputPassword, int dkLen);
+   
+   /**
+    * Convert String-based input to internal byte arrays, then invoke PBKDF2 and
+    * verify result against the reference data that is supplied in the
+    * PBKDF2Parameters.
+    * 
+    * @param inputPassword
+    *           Candidate password to compute the derived key for.
+    * @return <code>true</code> password match; <code>false</code> incorrect
+    *         password
+    */
+   public abstract boolean verifyKey(String inputPassword);
+   
+   /**
+    * Allow reading of configured parameters.
+    * 
+    * @return Currently set parameters.
+    */
+   public abstract PBKDF2Parameters getParameters();
+   
+   /**
+    * Allow setting of configured parameters.
+    * 
+    * @param parameters
+    */
+   public abstract void setParameters(PBKDF2Parameters parameters);
+   
+   /**
+    * Get currently set Pseudo Random Function.
+    * 
+    * @return Currently set Pseudo Random Function
+    */
+   public abstract PRF getPseudoRandomFunction();
+   
+   /**
+    * Set the Pseudo Random Function to use. Note that deriveKeys/getPRF does
+    * init this object using the supplied candidate password. If this is
+    * undesired, one has to override getPRF.
+    * 
+    * @param prf
+    *           Pseudo Random Function to set.
+    */
+   public abstract void setPseudoRandomFunction(PRF prf);
+}
\ No newline at end of file

Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Engine.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,340 @@
+package org.jboss.seam.security.crypto;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification
+ * <p>
+ * Version 2.0
+ * 
+ * <p>
+ * PBKDF2 (P, S, c, dkLen)
+ * 
+ * <p>
+ * Options:
+ * <ul>
+ * <li>PRF underlying pseudorandom function (hLen denotes the length in octets
+ * of the pseudorandom function output). PRF is pluggable.</li>
+ * </ul>
+ * 
+ * <p>
+ * Input:
+ * <ul>
+ * <li>P password, an octet string</li>
+ * <li>S salt, an octet string</li>
+ * <li>c iteration count, a positive integer</li>
+ * <li>dkLen intended length in octets of the derived key, a positive integer,
+ * at most (2^32 - 1) * hLen</li>
+ * </ul>
+ * 
+ * <p>
+ * Output:
+ * <ul>
+ * <li>DK derived key, a dkLen-octet string</li>
+ * </ul>
+ * 
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898</a>
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public class PBKDF2Engine implements PBKDF2
+{
+   protected PBKDF2Parameters parameters;
+   
+   protected PRF prf;
+   
+   /**
+    * Constructor for PBKDF2 implementation object. PBKDF2 parameters must be
+    * passed later.
+    */
+   public PBKDF2Engine()
+   {
+      this.parameters = null;
+      prf = null;
+   }
+   
+   /**
+    * Constructor for PBKDF2 implementation object. PBKDF2 parameters are passed
+    * so that this implementation knows iteration count, method to use and
+    * String encoding.
+    * 
+    * @param parameters
+    *           Data holder for iteration count, method to use et cetera.
+    */
+   public PBKDF2Engine(PBKDF2Parameters parameters)
+   {
+      this.parameters = parameters;
+      prf = null;
+   }
+   
+   /**
+    * Constructor for PBKDF2 implementation object. PBKDF2 parameters are passed
+    * so that this implementation knows iteration count, method to use and
+    * String encoding.
+    * 
+    * @param parameters
+    *           Data holder for iteration count, method to use et cetera.
+    * @param prf
+    *           Supply customer Pseudo Random Function.
+    */
+   public PBKDF2Engine(PBKDF2Parameters parameters, PRF prf)
+   {
+      this.parameters = parameters;
+      this.prf = prf;
+   }
+   
+   public byte[] deriveKey(String inputPassword)
+   {
+      return deriveKey(inputPassword, 0);
+   }
+   
+   public byte[] deriveKey(String inputPassword, int dkLen)
+   {
+      byte[] r = null;
+      byte P[] = null;
+      String charset = parameters.getHashCharset();
+      if (inputPassword == null)
+      {
+         inputPassword = "";
+      }
+      try
+      {
+         if (charset == null)
+         {
+            P = inputPassword.getBytes();
+         }
+         else
+         {
+            P = inputPassword.getBytes(charset);
+         }
+      }
+      catch (UnsupportedEncodingException e)
+      {
+         throw new RuntimeException(e);
+      }
+      assertPRF(P);
+      if (dkLen == 0)
+      {
+         dkLen = prf.getHLen();
+      }
+      r = PBKDF2(prf, parameters.getSalt(), parameters.getIterationCount(), dkLen);
+      return r;
+   }
+   
+   public boolean verifyKey(String inputPassword)
+   {
+      byte[] referenceKey = getParameters().getDerivedKey();
+      if (referenceKey == null || referenceKey.length == 0)
+      {
+         return false;
+      }
+      byte[] inputKey = deriveKey(inputPassword, referenceKey.length);
+      
+      if (inputKey == null || inputKey.length != referenceKey.length)
+      {
+         return false;
+      }
+      for (int i = 0; i < inputKey.length; i++)
+      {
+         if (inputKey[i] != referenceKey[i])
+         {
+            return false;
+         }
+      }
+      return true;
+   }
+   
+   /**
+    * Factory method. Default implementation is (H)MAC-based. To be overridden
+    * in derived classes.
+    * 
+    * @param P
+    *           User-supplied candidate password as array of bytes.
+    */
+   protected void assertPRF(byte[] P)
+   {
+      if (prf == null)
+      {
+         prf = new MacBasedPRF(parameters.getHashAlgorithm());
+      }
+      prf.init(P);
+   }
+   
+   public PRF getPseudoRandomFunction()
+   {
+      return prf;
+   }
+   
+   /**
+    * Core Password Based Key Derivation Function 2.
+    * 
+    * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2</a>
+    * @param prf
+    *           Pseudo Random Function (i.e. HmacSHA1)
+    * @param S
+    *           Salt as array of bytes. <code>null</code> means no salt.
+    * @param c
+    *           Iteration count (see RFC 2898 4.2)
+    * @param dkLen
+    *           desired length of derived key.
+    * @return internal byte array
+    */
+   protected byte[] PBKDF2(PRF prf, byte[] S, int c, int dkLen)
+   {
+      if (S == null)
+      {
+         S = new byte[0];
+      }
+      int hLen = prf.getHLen();
+      int l = ceil(dkLen, hLen);
+      int r = dkLen - (l - 1) * hLen;
+      byte T[] = new byte[l * hLen];
+      int ti_offset = 0;
+      for (int i = 1; i <= l; i++)
+      {
+         _F(T, ti_offset, prf, S, c, i);
+         ti_offset += hLen;
+      }
+      if (r < hLen)
+      {
+         // Incomplete last block
+         byte DK[] = new byte[dkLen];
+         System.arraycopy(T, 0, DK, 0, dkLen);
+         return DK;
+      }
+      return T;
+   }
+   
+   /**
+    * Integer division with ceiling function.
+    * 
+    * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 2.</a>
+    * @param a
+    * @param b
+    * @return ceil(a/b)
+    */
+   protected int ceil(int a, int b)
+   {
+      int m = 0;
+      if (a % b > 0)
+      {
+         m = 1;
+      }
+      return a / b + m;
+   }
+   
+   /**
+    * Function F.
+    * 
+    * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 3.</a>
+    * @param dest
+    *           Destination byte buffer
+    * @param offset
+    *           Offset into destination byte buffer
+    * @param prf
+    *           Pseudo Random Function
+    * @param S
+    *           Salt as array of bytes
+    * @param c
+    *           Iteration count
+    * @param blockIndex
+    */
+   protected void _F(byte[] dest, int offset, PRF prf, byte[] S, int c, int blockIndex)
+   {
+      int hLen = prf.getHLen();
+      byte U_r[] = new byte[hLen];
+      
+      // U0 = S || INT (i);
+      byte U_i[] = new byte[S.length + 4];
+      System.arraycopy(S, 0, U_i, 0, S.length);
+      INT(U_i, S.length, blockIndex);
+      
+      for (int i = 0; i < c; i++)
+      {
+         U_i = prf.doFinal(U_i);
+         xor(U_r, U_i);
+      }
+      System.arraycopy(U_r, 0, dest, offset, hLen);
+   }
+   
+   /**
+    * Block-Xor. Xor source bytes into destination byte buffer. Destination
+    * buffer must be same length or less than source buffer.
+    * 
+    * @param dest
+    * @param src
+    */
+   protected void xor(byte[] dest, byte[] src)
+   {
+      for (int i = 0; i < dest.length; i++)
+      {
+         dest[i] ^= src[i];
+      }
+   }
+   
+   /**
+    * Four-octet encoding of the integer i, most significant octet first.
+    * 
+    * @see <a href="http://tools.ietf.org/html/rfc2898">RFC 2898 5.2 Step 3.</a>
+    * @param dest
+    * @param offset
+    * @param i
+    */
+   protected void INT(byte[] dest, int offset, int i)
+   {
+      dest[offset + 0] = (byte) (i / (256 * 256 * 256));
+      dest[offset + 1] = (byte) (i / (256 * 256));
+      dest[offset + 2] = (byte) (i / (256));
+      dest[offset + 3] = (byte) (i);
+   }
+   
+   public PBKDF2Parameters getParameters()
+   {
+      return parameters;
+   }
+   
+   public void setParameters(PBKDF2Parameters parameters)
+   {
+      this.parameters = parameters;
+   }
+   
+   public void setPseudoRandomFunction(PRF prf)
+   {
+      this.prf = prf;
+   }
+}

Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Formatter.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,57 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public interface PBKDF2Formatter
+{
+    /**
+     * Convert parameters to String.
+     * 
+     * @param p
+     *            Parameters object to output.
+     * @return String representation
+     */
+    public abstract String toString(PBKDF2Parameters p);
+
+    /**
+     * Convert String to parameters. Depending on actual implementation, it may
+     * be required to set further fields externally.
+     * 
+     * @param s
+     *            String representation of parameters to decode.
+     * @return <code>false</code> syntax OK, <code>true</code> some syntax
+     *         issue.
+     */
+    public abstract boolean fromString(PBKDF2Parameters p, String s);
+}
\ No newline at end of file

Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2HexFormatter.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,68 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public class PBKDF2HexFormatter implements PBKDF2Formatter
+{
+    public boolean fromString(PBKDF2Parameters p, String s)
+    {
+        if (p == null || s == null)
+        {
+            return true;
+        }
+
+        String[] p123 = s.split(":");
+        if (p123 == null || p123.length != 3)
+        {
+            return true;
+        }
+
+        byte salt[] = BinTools.hex2bin(p123[0]);
+        int iterationCount = Integer.parseInt(p123[1]);
+        byte bDK[] = BinTools.hex2bin(p123[2]);
+
+        p.setSalt(salt);
+        p.setIterationCount(iterationCount);
+        p.setDerivedKey(bDK);
+        return false;
+    }
+
+    public String toString(PBKDF2Parameters p)
+    {
+        String s = BinTools.bin2hex(p.getSalt()) + ":"
+                + String.valueOf(p.getIterationCount()) + ":"
+                + BinTools.bin2hex(p.getDerivedKey());
+        return s;
+    }
+}
\ No newline at end of file

Added: trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PBKDF2Parameters.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,165 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * Parameter data holder for PBKDF2 configuration.
+ * </p>
+ * 
+ * <hr />
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public class PBKDF2Parameters
+{
+   protected byte[] salt;
+   
+   protected int iterationCount;
+   
+   protected String hashAlgorithm;
+   
+   protected String hashCharset;
+   
+   /**
+    * The derived key is actually only a convenience to store a reference
+    * derived key. It is not used during computation.
+    */
+   protected byte[] derivedKey;
+   
+   /**
+    * Constructor. Defaults to <code>null</code> for byte arrays, UTF-8 as
+    * character set and 1000 for iteration count.
+    * 
+    */
+   public PBKDF2Parameters()
+   {
+      this.hashAlgorithm = null;
+      this.hashCharset = "UTF-8";
+      this.salt = null;
+      this.iterationCount = 1000;
+      this.derivedKey = null;
+   }
+   
+   /**
+    * Constructor.
+    * 
+    * @param hashAlgorithm
+    *           for example HMacSHA1 or HMacMD5
+    * @param hashCharset
+    *           for example UTF-8
+    * @param salt
+    *           Salt as byte array, may be <code>null</code> (not recommended)
+    * @param iterationCount
+    *           Number of iterations to execute. Recommended value 1000.
+    */
+   public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount)
+   {
+      this.hashAlgorithm = hashAlgorithm;
+      this.hashCharset = hashCharset;
+      this.salt = salt;
+      this.iterationCount = iterationCount;
+      this.derivedKey = null;
+   }
+   
+   /**
+    * Constructor.
+    * 
+    * @param hashAlgorithm
+    *           for example HMacSHA1 or HMacMD5
+    * @param hashCharset
+    *           for example UTF-8
+    * @param salt
+    *           Salt as byte array, may be <code>null</code> (not recommended)
+    * @param iterationCount
+    *           Number of iterations to execute. Recommended value 1000.
+    * @param derivedKey
+    *           Convenience data holder, not used during computation.
+    */
+   public PBKDF2Parameters(String hashAlgorithm, String hashCharset, byte[] salt, int iterationCount, byte[] derivedKey)
+   {
+      this.hashAlgorithm = hashAlgorithm;
+      this.hashCharset = hashCharset;
+      this.salt = salt;
+      this.iterationCount = iterationCount;
+      this.derivedKey = derivedKey;
+   }
+   
+   public int getIterationCount()
+   {
+      return iterationCount;
+   }
+   
+   public void setIterationCount(int iterationCount)
+   {
+      this.iterationCount = iterationCount;
+   }
+   
+   public byte[] getSalt()
+   {
+      return salt;
+   }
+   
+   public void setSalt(byte[] salt)
+   {
+      this.salt = salt;
+   }
+   
+   public byte[] getDerivedKey()
+   {
+      return derivedKey;
+   }
+   
+   public void setDerivedKey(byte[] derivedKey)
+   {
+      this.derivedKey = derivedKey;
+   }
+   
+   public String getHashAlgorithm()
+   {
+      return hashAlgorithm;
+   }
+   
+   public void setHashAlgorithm(String hashAlgorithm)
+   {
+      this.hashAlgorithm = hashAlgorithm;
+   }
+   
+   public String getHashCharset()
+   {
+      return hashCharset;
+   }
+   
+   public void setHashCharset(String hashCharset)
+   {
+      this.hashCharset = hashCharset;
+   }
+}

Added: trunk/src/main/org/jboss/seam/security/crypto/PRF.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/crypto/PRF.java	                        (rev 0)
+++ trunk/src/main/org/jboss/seam/security/crypto/PRF.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -0,0 +1,64 @@
+package org.jboss.seam.security.crypto;
+
+/**
+ * Copied from Matthias Gartner's PKCS#5 implementation - see
+ * http://rtner.de/software/PBKDF2.html
+ * 
+ * <p>
+ * A free Java implementation of Password Based Key Derivation Function 2 as
+ * defined by RFC 2898. Copyright (c) 2007 Matthias G&auml;rtner
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * This library 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.
+ * </p>
+ * <p>
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * </p>
+ * <p>
+ * For Details, see <a
+ * href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
+ * >http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</a>.
+ * </p>
+ * 
+ * @author Matthias G&auml;rtner
+ * @version 1.0
+ */
+public interface PRF
+{
+   /**
+    * Initialize this instance with the user-supplied password.
+    * 
+    * @param P
+    *           The password supplied as array of bytes. It is the caller's task
+    *           to convert String passwords to bytes as appropriate.
+    */
+   public void init(byte[] P);
+   
+   /**
+    * Pseudo Random Function
+    * 
+    * @param M
+    *           Input data/message etc. Together with any data supplied during
+    *           initilization.
+    * @return Random bytes of hLen length.
+    */
+   public byte[] doFinal(byte[] M);
+   
+   /**
+    * Query block size of underlying algorithm/mechanism.
+    * 
+    * @return block size
+    */
+   public int getHLen();
+}
\ No newline at end of file

Modified: trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java	2009-04-14 23:58:24 UTC (rev 10418)
+++ trunk/src/main/org/jboss/seam/security/management/JpaIdentityStore.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -43,8 +43,8 @@
 import org.jboss.seam.security.Identity;
 import org.jboss.seam.security.Role;
 import org.jboss.seam.security.SimplePrincipal;
+import org.jboss.seam.security.crypto.BinTools;
 import org.jboss.seam.util.AnnotatedBeanProperty;
-import org.jboss.seam.util.Base64;
 import org.jboss.seam.util.TypedBeanProperty;
 
 /**
@@ -254,7 +254,7 @@
       if (passwordSaltProperty.isSet())
       {
          byte[] salt = generateUserSalt(user);               
-         passwordSaltProperty.setValue(user, Base64.encodeBytes(salt));
+         passwordSaltProperty.setValue(user, BinTools.bin2hex(salt));
          userPasswordProperty.setValue(user, generatePasswordHash(password, salt));
       }
       else
@@ -821,7 +821,7 @@
                   ", but it contains no value");
          }
          
-         passwordHash = generatePasswordHash(password, Base64.decode(encodedSalt));
+         passwordHash = generatePasswordHash(password, BinTools.hex2bin(encodedSalt));
       }
       else
       {

Modified: trunk/src/main/org/jboss/seam/security/management/PasswordHash.java
===================================================================
--- trunk/src/main/org/jboss/seam/security/management/PasswordHash.java	2009-04-14 23:58:24 UTC (rev 10418)
+++ trunk/src/main/org/jboss/seam/security/management/PasswordHash.java	2009-04-15 06:41:04 UTC (rev 10419)
@@ -10,7 +10,6 @@
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
-import javax.crypto.spec.SecretKeySpec;
 
 import org.jboss.seam.Component;
 import org.jboss.seam.ScopeType;
@@ -18,6 +17,10 @@
 import org.jboss.seam.annotations.Name;
 import org.jboss.seam.annotations.Scope;
 import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.security.crypto.BinTools;
+import org.jboss.seam.security.crypto.PBKDF2;
+import org.jboss.seam.security.crypto.PBKDF2Engine;
+import org.jboss.seam.security.crypto.PBKDF2Parameters;
 import org.jboss.seam.util.Base64;
 
 /**
@@ -36,7 +39,15 @@
         
    private static final String DEFAULT_ALGORITHM = ALGORITHM_MD5;
    
-   private int saltLength = 8; // default password salt length, in bytes
+   /*
+    * If specified, use the JCE instead of the built in algorithm
+    */
+   private String hashAlgorithm = null;
+
+   /*
+    *  default password salt length, in bytes
+    */
+   private int saltLength = 8; 
       
    @Deprecated
    public String generateHash(String password)
@@ -100,12 +111,20 @@
    public String createPasswordKey(char[] password, byte[] salt, int iterations) 
       throws GeneralSecurityException 
    {
-      PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
-      SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
-      SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
-      passwordKeySpec.clearPassword();
-      byte[] encoded = passwordKey.getEncoded();
-      return Base64.encodeBytes(new SecretKeySpec(encoded, "AES").getEncoded());
+      if (hashAlgorithm != null)
+      {
+         PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
+         SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(hashAlgorithm);
+         SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
+         passwordKeySpec.clearPassword();
+         return BinTools.bin2hex(passwordKey.getEncoded());
+      }
+      else
+      {
+         PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, iterations);
+         PBKDF2 pbkdf2 = new PBKDF2Engine(params);
+         return BinTools.bin2hex(pbkdf2.deriveKey(new String(password)));
+      }
    }
    
    public static PasswordHash instance()
@@ -113,6 +132,16 @@
       return (PasswordHash) Component.getInstance(PasswordHash.class, ScopeType.STATELESS);
    }
    
+   public String getHashAlgorithm()
+   {
+      return hashAlgorithm;
+   }
+   
+   public void setHashAlgorithm(String hashAlgorithm)
+   {
+      this.hashAlgorithm = hashAlgorithm;
+   }
+   
    public int getSaltLength()
    {
       return saltLength;




More information about the seam-commits mailing list