[jboss-cvs] Picketbox SVN: r112 - in trunk/security-spi/spi/src: test/java/org/jboss/test/security/otp and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Sep 20 17:17:37 EDT 2010


Author: anil.saldhana at jboss.com
Date: 2010-09-20 17:17:37 -0400 (Mon, 20 Sep 2010)
New Revision: 112

Added:
   trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTP.java
   trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTPUtil.java
   trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/TimeBasedOTPUnitTestCase.java
Modified:
   trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTPUtil.java
   trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java
Log:
SECURITY-529: TOTP algo

Modified: trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTPUtil.java
===================================================================
--- trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTPUtil.java	2010-09-15 20:10:30 UTC (rev 111)
+++ trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTPUtil.java	2010-09-20 21:17:37 UTC (rev 112)
@@ -21,8 +21,7 @@
  */
 package org.jboss.security.otp;
 
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
 import java.util.Calendar;
 import java.util.TimeZone;
 
@@ -41,10 +40,9 @@
     * @param secret Shared secret
     * @param timeValueInMins How many mins back we need to check?
     * @return
-    * @throws InvalidKeyException
-    * @throws NoSuchAlgorithmException
+    * @throws GeneralSecurityException 
     */
-   public static boolean validate( String submittedOTP, byte[] secret, int timeValueInMins ) throws InvalidKeyException, NoSuchAlgorithmException
+   public static boolean validate( String submittedOTP, byte[] secret, int timeValueInMins ) throws GeneralSecurityException
    {
       int codeDigits = 6;
       boolean addChecksum = false;

Added: trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTP.java
===================================================================
--- trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTP.java	                        (rev 0)
+++ trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTP.java	2010-09-20 21:17:37 UTC (rev 112)
@@ -0,0 +1,225 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.security.otp;
+
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * TOTP: Time-based One-time Password Algorithm
+ * Based on http://tools.ietf.org/html/draft-mraihi-totp-timebased-06
+ * 
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 20, 2010
+ */
+public class TimeBasedOTP
+{
+   private static final String HMAC_SHA1 = "HmacSHA1";
+
+   private static final String HMAC_SHA256 = "HmacSHA256";
+   
+   private static final String HMAC_SHA512 = "HmacSHA512";
+   
+   // 0 1  2   3    4     5      6       7        8
+   private static final int[] DIGITS_POWER  = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; 
+
+   private static int TIME_SLICE_X = 30000;
+   private static int TIME_ZERO = 0;
+   
+   
+   /**
+    * Generate a TOTP value using HMAC_SHA1
+    * @param key
+    * @param returnDigits
+    * @return
+    * @throws GeneralSecurityException
+    */
+   public static String generateTOTP( String key, int returnDigits ) throws GeneralSecurityException
+   {
+      TimeZone utc = TimeZone.getTimeZone( "UTC" );
+      Calendar currentDateTime = Calendar.getInstance( utc );
+      long timeInMilis = currentDateTime.getTimeInMillis();
+       
+      String steps = "0";
+      long T = ( timeInMilis - TIME_ZERO ) /  TIME_SLICE_X ; 
+      steps = Long.toHexString( T ).toUpperCase();
+      
+      // Just get a 16 digit string
+      while(steps.length() < 16) 
+         steps = "0" + steps;
+      return TimeBasedOTP.generateTOTP( key, steps, returnDigits); 
+   }
+   
+   /**
+    * This method generates an TOTP value for the given
+    * set of parameters.
+    *
+    * @param key   the shared secret, HEX encoded
+    * @param time     a value that reflects a time
+    * @param returnDigits     number of digits to return
+    *
+    * @return      A numeric String in base 10 that includes
+    *              {@link truncationDigits} digits
+    * @throws GeneralSecurityException 
+    */
+   public static String generateTOTP( String key,   String time, int returnDigits ) throws GeneralSecurityException
+   {
+      return generateTOTP( key, time, returnDigits, HMAC_SHA1 );
+   }
+
+
+   /**
+    * This method generates an TOTP value for the given
+    * set of parameters.
+    *
+    * @param key   the shared secret, HEX encoded
+    * @param time     a value that reflects a time
+    * @param returnDigits     number of digits to return
+    *
+    * @return      A numeric String in base 10 that includes
+    *              {@link truncationDigits} digits
+    * @throws GeneralSecurityException 
+    */
+   public static String generateTOTP256(String key, String time, int returnDigits) throws GeneralSecurityException
+   {
+      return generateTOTP( key, time, returnDigits, HMAC_SHA256 );
+   }
+
+
+   /**
+    * This method generates an TOTP value for the given
+    * set of parameters.
+    *
+    * @param key   the shared secret, HEX encoded
+    * @param time     a value that reflects a time
+    * @param returnDigits     number of digits to return
+    *
+    * @return      A numeric String in base 10 that includes
+    *              {@link truncationDigits} digits
+    * @throws GeneralSecurityException 
+    */
+   public static String generateTOTP512(String key, String time, int returnDigits) throws GeneralSecurityException
+   {
+      return generateTOTP( key, time, returnDigits, HMAC_SHA512 );
+   }
+  
+   /**
+    * This method generates an TOTP value for the given
+    * set of parameters.
+    *
+    * @param key   the shared secret, HEX encoded
+    * @param time     a value that reflects a time
+    * @param returnDigits     number of digits to return
+    * @param crypto    the crypto function to use
+    *
+    * @return      A numeric String in base 10 that includes
+    *              {@link truncationDigits} digits
+    * @throws GeneralSecurityException 
+    */
+   public static String generateTOTP(String key, String time,  int returnDigits, String crypto) throws GeneralSecurityException
+   { 
+      String result = null;
+      byte[] hash;
+
+      // Using the counter
+      // First 8 bytes are for the movingFactor
+      // Complaint with base RFC 4226 (HOTP)
+      while(time.length() < 16 )
+         time = "0" + time;
+
+      // Get the HEX in a Byte[]
+      byte[] msg = hexStr2Bytes(time);
+
+      // Adding one byte to get the right conversion
+      byte[] k = hexStr2Bytes(key);
+
+      hash = hmac_sha1(crypto, k, msg);
+
+      // put selected bytes into result int
+      int offset = hash[hash.length - 1] & 0xf;
+
+      int binary =
+         ((hash[offset] & 0x7f) << 24) |
+         ((hash[offset + 1] & 0xff) << 16) |
+         ((hash[offset + 2] & 0xff) << 8) |
+         (hash[offset + 3] & 0xff);
+
+      int otp = binary % DIGITS_POWER[ returnDigits ];
+
+      result = Integer.toString(otp);
+      while (result.length() < returnDigits ) {
+         result = "0" + result;
+      }
+      return result;
+   }
+   
+   /**
+    * This method uses the JCE to provide the crypto
+    * algorithm.
+    * HMAC computes a Hashed Message Authentication Code with the
+    * crypto hash algorithm as a parameter.
+    *
+    * @param crypto     the crypto algorithm (HmacSHA1, HmacSHA256,
+    *                            HmacSHA512)
+    * @param keyBytes   the bytes to use for the HMAC key
+    * @param text       the message or text to be authenticated.
+    * @throws NoSuchAlgorithmException 
+    * @throws InvalidKeyException 
+    */
+   private static byte[] hmac_sha1(String crypto, byte[] keyBytes, byte[] text) throws GeneralSecurityException
+   {
+      Mac hmac;
+      hmac = Mac.getInstance(crypto);
+      SecretKeySpec macKey =
+         new SecretKeySpec(keyBytes, "RAW");
+      hmac.init(macKey);
+      return hmac.doFinal(text);
+   }
+
+
+   /**
+    * This method converts HEX string to Byte[]
+    *
+    * @param hex   the HEX string
+    *
+    * @return      A byte array
+    */
+   private static byte[] hexStr2Bytes(String hex)
+   {
+      // Adding one byte to get the right conversion
+      // values starting with "0" can be converted
+      byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
+
+      // Copy all the REAL bytes, not the "first"
+      byte[] ret = new byte[bArray.length - 1];
+      for (int i = 0; i < ret.length ; i++)
+         ret[i] = bArray[i+1];
+      return ret;
+   }
+}
\ No newline at end of file

Added: trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTPUtil.java
===================================================================
--- trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTPUtil.java	                        (rev 0)
+++ trunk/security-spi/spi/src/main/java/org/jboss/security/otp/TimeBasedOTPUtil.java	2010-09-20 21:17:37 UTC (rev 112)
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.security.otp;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * Utility class associated with the {@code TimeBasedOTP} class
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 20, 2010
+ */
+public class TimeBasedOTPUtil
+{   
+   /**
+   * Validate a submitted OTP string
+   * @param submittedOTP OTP string to validate
+   * @param secret Shared secret 
+   * @return 
+   * @throws GeneralSecurityException
+   */
+  public static boolean validate( String submittedOTP, byte[] secret, int numDigits ) throws GeneralSecurityException
+  {
+     String generatedTOTP = TimeBasedOTP.generateTOTP( new String( secret ) , numDigits ); 
+     
+     System.out.println( "Generated[" + generatedTOTP + "]::Submitted[" + submittedOTP );
+     return generatedTOTP.equals( submittedOTP ); 
+  } 
+}
\ No newline at end of file

Modified: trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java
===================================================================
--- trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java	2010-09-15 20:10:30 UTC (rev 111)
+++ trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java	2010-09-20 21:17:37 UTC (rev 112)
@@ -70,7 +70,7 @@
       //System.out.println( "OTP Generated at " + currentDateTime);
       
       System.out.println( "We are going to sleep for " + SLEEP_TIME + " secs" );
-      Thread.sleep( SLEEP_TIME * 1000 ); //20 secs
+      Thread.sleep( SLEEP_TIME * 1000 ); //10 secs
       
       assertTrue( HOTPUtil.validate( otp1, secret,  2 ) );
    }

Added: trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/TimeBasedOTPUnitTestCase.java
===================================================================
--- trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/TimeBasedOTPUnitTestCase.java	                        (rev 0)
+++ trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/TimeBasedOTPUnitTestCase.java	2010-09-20 21:17:37 UTC (rev 112)
@@ -0,0 +1,123 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.test.security.otp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.jboss.security.otp.TimeBasedOTP;
+import org.jboss.security.otp.TimeBasedOTPUtil;
+import org.junit.Test;
+
+/**
+ * Unit test the {@code TimeBasedOTP} utility
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 20, 2010
+ */
+public class TimeBasedOTPUnitTestCase
+{ 
+   /**
+    | Time (sec) |    UTC Time   | Value of T (hex) |   TOTP   |  Mode  |
+   +------------+---------------+------------------+----------+--------+
+   |     59     |   1970-01-01  | 0000000000000001 | 94287082 |  SHA1  |
+   |            |    00:00:59   |                  |          |        |
+   |     59     |   1970-01-01  | 0000000000000001 | 32247374 | SHA256 |
+   |            |    00:00:59   |                  |          |        |
+   |     59     |   1970-01-01  | 0000000000000001 | 69342147 | SHA512 |
+   |            |    00:00:59   |                  |          |        |
+   | 1111111109 |   2005-03-18  | 00000000023523EC | 07081804 |  SHA1  |
+   |            |    01:58:29   |                  |          |        |
+   | 1111111109 |   2005-03-18  | 00000000023523EC | 34756375 | SHA256 |
+   |            |    01:58:29   |                  |          |        |
+   | 1111111109 |   2005-03-18  | 00000000023523EC | 63049338 | SHA512 |
+   |            |    01:58:29   |                  |          |        |
+   | 1111111111 |   2005-03-18  | 00000000023523ED | 14050471 |  SHA1  |
+   |            |    01:58:31   |                  |          |        |
+   | 1111111111 |   2005-03-18  | 00000000023523ED | 74584430 | SHA256 |
+   |            |    01:58:31   |                  |          |        |
+   | 1111111111 |   2005-03-18  | 00000000023523ED | 54380122 | SHA512 |
+   |            |    01:58:31   |                  |          |        |
+   | 1234567890 |   2009-02-13  | 000000000273EF07 | 89005924 |  SHA1  |
+   |            |    23:31:30   |                  |          |        |
+   | 1234567890 |   2009-02-13  | 000000000273EF07 | 42829826 | SHA256 |
+   |            |    23:31:30   |                  |          |        |
+   | 1234567890 |   2009-02-13  | 000000000273EF07 | 76671578 | SHA512 |
+   |            |    23:31:30   |                  |          |        |
+   | 2000000000 |   2033-05-18  | 0000000003F940AA | 69279037 |  SHA1  |
+   |            |    03:33:20   |                  |          |        |
+   | 2000000000 |   2033-05-18  | 0000000003F940AA | 78428693 | SHA256 |
+   |            |    03:33:20   |                  |          |        |
+   | 2000000000 |   2033-05-18  | 0000000003F940AA | 56464532 | SHA512 |
+   |            |    03:33:20   |                  |          |        |
+   +------------+---------------+------------------+----------+--------+
+
+    */
+ 
+   String seed = "3132333435363738393031323334353637383930";
+   long T0 = 0;
+   long X = 30;
+   long testTime[] = { 59, 1111111109, 1111111111, 1234567890, 2000000000 };
+   
+   String steps = "0";
+   
+   String[] totp = new String[] { "94287082", "32247374", "69342147",
+                                  "07081804", "34756375", "63049338",
+                                  "14050471", "74584430", "54380122",
+                                  "89005924", "42829826", "76671578",
+                                  "69279037", "78428693", "56464532" };
+   
+   int NUMBER_OF_DIGITS = 8;
+   
+   int SLEEP_TIME = 10;
+   
+   
+   @Test
+   public void testTOTP() throws Exception
+   {
+      int totpIndex = -1;
+      
+      for(int i=0; i< testTime.length; i++) 
+      {
+         long T = ( testTime[i] - T0 ) / X;
+         steps = Long.toHexString( T ).toUpperCase();
+         
+         // Just get a 16 digit string
+         while(steps.length() < 16) 
+            steps = "0" + steps;
+         
+         assertEquals( totp[ ++totpIndex ], TimeBasedOTP.generateTOTP( seed, steps, NUMBER_OF_DIGITS , "HmacSHA1" ) );
+         assertEquals( totp[ ++totpIndex ], TimeBasedOTP.generateTOTP( seed, steps, NUMBER_OF_DIGITS , "HmacSHA256" ) );
+         assertEquals( totp[ ++totpIndex ], TimeBasedOTP.generateTOTP( seed, steps, NUMBER_OF_DIGITS , "HmacSHA512" ) ); 
+     } 
+   } 
+   
+   @Test
+   public void testTOTPValidity() throws Exception
+   {         
+      String totp = TimeBasedOTP.generateTOTP( seed, NUMBER_OF_DIGITS ); 
+
+      System.out.println( "We are going to sleep for " + SLEEP_TIME + " secs" );
+      Thread.sleep( SLEEP_TIME * 1000 ); //10 secs
+      
+      assertTrue( "TOTP validated", TimeBasedOTPUtil.validate( totp, seed.getBytes() , 8 ));
+   }
+}
\ No newline at end of file



More information about the jboss-cvs-commits mailing list