[jboss-cvs] Picketbox SVN: r109 - in trunk/security-spi/spi/src: main/java/org/jboss/security/otp and 2 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Wed Sep 15 15:41:51 EDT 2010
Author: anil.saldhana at jboss.com
Date: 2010-09-15 15:41:51 -0400 (Wed, 15 Sep 2010)
New Revision: 109
Added:
trunk/security-spi/spi/src/main/java/org/jboss/security/otp/
trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTP.java
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/
trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java
Log:
SECURITY-526: otp library
Added: trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTP.java
===================================================================
--- trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTP.java (rev 0)
+++ trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTP.java 2010-09-15 19:41:51 UTC (rev 109)
@@ -0,0 +1,192 @@
+/*
+ * 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.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Based on IETF RFC 4226 (http://tools.ietf.org/html/rfc4226)
+ * Code is derived from OATH HOTP algorithm
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 13, 2010
+ */
+public class HOTP
+{
+ private static final int[] doubleDigits = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 };
+
+ // 0 1 2 3 4 5 6 7 8
+ private static final int[] DIGITS_POWER = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
+
+ /**
+ * This method generates an OTP value for the given set of parameters.
+ *
+ * @param secret the shared secret
+ * @param movingFactor the counter, time, or other value that
+ * changes on a per use basis.
+ * @param codeDigits the number of digits in the OTP, not
+ * including the checksum, if any.
+ * @param addChecksum a flag that indicates if a checksum digit
+
+ * should be appended to the OTP.
+ * @param truncationOffset the offset into the MAC result to
+ * begin truncation. If this value is out of
+ * the range of 0 ... 15, then dynamic
+ * truncation will be used.
+ * Dynamic truncation is when the last 4
+ * bits of the last byte of the MAC are
+ * used to determine the start offset.
+ * @throws NoSuchAlgorithmException if no provider makes
+ * either HmacSHA1 or HMAC-SHA-1
+ * digest algorithms available.
+ * @throws InvalidKeyException
+ * The secret provided was not
+ * a valid HMAC-SHA-1 key.
+ *
+ * @return A numeric String in base 10 that includes
+ * {@link codeDigits} digits plus the optional checksum
+ * digit if requested.
+ */
+ public static String generateOTP(byte[] secret,
+ long movingFactor,
+ int codeDigits,
+ boolean addChecksum,
+ int truncationOffset)
+ throws NoSuchAlgorithmException, InvalidKeyException
+ {
+ // put movingFactor value into text byte array
+ String result = null;
+ int digits = addChecksum ? (codeDigits + 1) : codeDigits;
+ byte[] text = new byte[8];
+
+ for (int i = text.length - 1; i >= 0; i--)
+ {
+ text[i] = (byte) (movingFactor & 0xff);
+ movingFactor >>= 8;
+ }
+
+ // compute hmac hash
+ byte[] hash = hmac_sha1(secret, text);
+
+ // put selected bytes into result int
+ int offset = hash[hash.length - 1] & 0xf;
+ if ( (0<=truncationOffset) &&
+ (truncationOffset<(hash.length-4)) )
+ {
+ offset = truncationOffset;
+ }
+
+ 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[codeDigits];
+ if (addChecksum)
+ {
+ otp = (otp * 10) + calcChecksum(otp, codeDigits);
+ }
+ result = Integer.toString(otp);
+
+ while (result.length() < digits)
+ {
+ result = "0" + result;
+ }
+ return result;
+ }
+
+ /**
+ * Calculates the checksum using the credit card algorithm.
+ * This algorithm has the advantage that it detects any single
+ * mistyped digit and any single transposition of
+ * adjacent digits.
+ *
+ * @param num the number to calculate the checksum for
+ * @param digits number of significant places in the number
+ *
+ * @return the checksum of num
+ */
+ private static int calcChecksum(long num, int digits)
+ {
+ boolean doubleDigit = true;
+
+ int total = 0;
+
+ while (0 < digits--)
+ {
+ int digit = (int) (num % 10);
+ num /= 10;
+ if (doubleDigit)
+ {
+ digit = doubleDigits[digit];
+ }
+ total += digit;
+ doubleDigit = !doubleDigit;
+ }
+
+ int result = total % 10;
+
+ if (result > 0)
+ {
+ result = 10 - result;
+ }
+ return result;
+ }
+
+ /**
+ * This method uses the JCE to provide the HMAC-SHA-1 algorithm.
+ * HMAC computes a Hashed Message Authentication Code and
+ * in this case SHA1 is the hash algorithm used.
+ *
+ * @param keyBytes the bytes to use for the HMAC-SHA-1 key
+ * @param text the message or text to be authenticated.
+ *
+ * @throws NoSuchAlgorithmException if no provider makes
+ * either HmacSHA1 or HMAC-SHA-1
+ * digest algorithms available.
+ * @throws InvalidKeyException
+ * The secret provided was not a valid HMAC-SHA-1 key.
+ *
+ */
+ private static byte[] hmac_sha1( byte[] keyBytes, byte[] text )
+ throws NoSuchAlgorithmException, InvalidKeyException
+ {
+ Mac hmacSha1;
+ try
+ {
+ hmacSha1 = Mac.getInstance("HmacSHA1");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ hmacSha1 = Mac.getInstance("HMAC-SHA-1");
+ }
+
+ SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
+ hmacSha1.init(macKey);
+
+ return hmacSha1.doFinal(text);
+ }
+}
\ No newline at end of file
Added: 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 (rev 0)
+++ trunk/security-spi/spi/src/main/java/org/jboss/security/otp/HOTPUtil.java 2010-09-15 19:41:51 UTC (rev 109)
@@ -0,0 +1,75 @@
+/*
+ * 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.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Utility class for {@code HOTP}
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 15, 2010
+ */
+public class HOTPUtil
+{
+ private static final int MILISECOND_BUFFER = 50;
+
+ /**
+ * Validate a submitted OTP string
+ * @param submittedOTP OTP string to validate
+ * @param secret Shared secret
+ * @param timeValueInMins How many mins back we need to check?
+ * @return
+ * @throws InvalidKeyException
+ * @throws NoSuchAlgorithmException
+ */
+ public static boolean validate( String submittedOTP, byte[] secret, int timeValueInMins ) throws InvalidKeyException, NoSuchAlgorithmException
+ {
+ int codeDigits = 6;
+ boolean addChecksum = false;
+ int truncationOffset = 0;
+
+ TimeZone utc = TimeZone.getTimeZone( "UTC" );
+ Calendar currentDateTime = Calendar.getInstance( utc );
+
+ long timeInMilis = currentDateTime.getTimeInMillis();
+ long movingFactor = timeInMilis;
+
+ String otp = HOTP.generateOTP( secret, movingFactor, codeDigits, addChecksum, truncationOffset );
+
+ if( otp.equals( submittedOTP ) )
+ return true;
+
+ int endLimit = timeValueInMins * 60* 1000 + MILISECOND_BUFFER;
+
+ for( int i = 1; i < endLimit ; i++ )
+ {
+ movingFactor --;
+ otp = HOTP.generateOTP( secret, movingFactor, codeDigits, addChecksum, truncationOffset );
+ if( otp.equals( submittedOTP ) )
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
Added: 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 (rev 0)
+++ trunk/security-spi/spi/src/test/java/org/jboss/test/security/otp/HOTPUnitTestCase.java 2010-09-15 19:41:51 UTC (rev 109)
@@ -0,0 +1,85 @@
+/*
+ * 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 java.util.Calendar;
+import java.util.TimeZone;
+
+import org.jboss.security.otp.HOTP;
+import org.jboss.security.otp.HOTPUtil;
+import org.junit.Test;
+
+/**
+ * Unit test the {@code HOTP}
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 13, 2010
+ */
+public class HOTPUnitTestCase
+{
+ private String userCode = "SomeCode";
+
+ private int codeDigits = 6;
+ private boolean addChecksum = false;
+ private int truncationOffset = 0;
+
+ byte[] secret = userCode.getBytes();
+
+ int SLEEP_TIME = 10;
+
+ @Test
+ public void testHOTP() throws Exception
+ {
+ TimeZone utc = TimeZone.getTimeZone( "UTC" );
+ Calendar currentDateTime = Calendar.getInstance( utc );
+
+ String otp1 = this.getOTP(secret, currentDateTime);
+ String otp2 = this.getOTP(secret, currentDateTime);
+
+ assertEquals( otp1, otp2 );
+ }
+
+ @Test
+ public void testSubmittedHOTP() throws Exception
+ {
+ TimeZone utc = TimeZone.getTimeZone( "UTC" );
+ Calendar currentDateTime = Calendar.getInstance( utc );
+ String otp1 = this.getOTP( secret, currentDateTime );
+
+ //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
+
+ assertTrue( HOTPUtil.validate( otp1, secret, 2 ) );
+ }
+
+ private String getOTP( byte[] secret, Calendar currentDateTime ) throws Exception
+ {
+ long timeInMilis = currentDateTime.getTimeInMillis();
+ long movingFactor = timeInMilis;
+
+ return HOTP.generateOTP( secret, movingFactor, codeDigits, addChecksum, truncationOffset );
+ }
+}
\ No newline at end of file
More information about the jboss-cvs-commits
mailing list