[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