diff options
| -rw-r--r-- | libs/bcprov-jdk15on-148.jar | bin | 2318161 -> 0 bytes | |||
| -rw-r--r-- | src/org/jboss/security/srp/SRPClientSession.java | 289 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPConf.java | 113 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPParameters.java | 150 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPPermission.java | 66 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPServerListener.java | 42 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPServerSession.java | 285 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPSessionKey.java | 78 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SRPVerifierStore.java | 115 | ||||
| -rw-r--r-- | src/org/jboss/security/srp/SerialObjectStore.java | 216 | ||||
| -rw-r--r-- | src/se/leap/leapclient/ProviderAPI.java | 23 | 
11 files changed, 1374 insertions, 3 deletions
diff --git a/libs/bcprov-jdk15on-148.jar b/libs/bcprov-jdk15on-148.jar Binary files differdeleted file mode 100644 index 3fcb136..0000000 --- a/libs/bcprov-jdk15on-148.jar +++ /dev/null diff --git a/src/org/jboss/security/srp/SRPClientSession.java b/src/org/jboss/security/srp/SRPClientSession.java new file mode 100644 index 0000000..bafc484 --- /dev/null +++ b/src/org/jboss/security/srp/SRPClientSession.java @@ -0,0 +1,289 @@ +/* + * 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.srp; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import org.jboss.crypto.CryptoUtil; +import org.jboss.logging.Logger;  + +/** The client side logic to the SRP protocol. The class is intended to be used + * with a SRPServerSession object via the SRPServerInterface. The SRP algorithm + * using these classes consists of: + * + * 1. Get server, SRPServerInterface server = (SRPServerInterface) Naming.lookup(...); + * 2. Get SRP parameters, SRPParameters params = server.getSRPParameters(username); + * 3. Create a client session, SRPClientSession client = new SRPClientSession(username, + * password, params); + * 4. Exchange public keys, byte[] A = client.exponential(); + * byte[] B = server.init(username, A); + * 5. Exchange challenges, byte[] M1 = client.response(B); + * byte[] M2 = server.verify(username, M1); + * 6. Verify the server response, if( client.verify(M2) == false ) + * throw new SecurityException("Failed to validate server reply"); + * 7. Validation complete + * + * Note that these steps are stateful. They must be performed in order and a + * step cannot be repeated to update the session state. + * + * This product uses the 'Secure Remote Password' cryptographic + * authentication system developed by Tom Wu (tjw@CS.Stanford.EDU). + * + * @author Scott.Stark@jboss.org + * @version $Revision: 81038 $ + */ +public class SRPClientSession +{ +   private static Logger log = Logger.getLogger(SRPClientSession.class); +   private SRPParameters params; +   private BigInteger N; +   private BigInteger g; +   private BigInteger x; +   private BigInteger v; +   private byte[] s; +   private BigInteger a; +   private BigInteger A; +   private byte[] K; +   /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ +   private MessageDigest clientHash; +   /** The M2 = H(A | M | K) hash */ +   private MessageDigest serverHash; +    +   private static int A_LEN = 64; +    +   /** Creates a new SRP server session object from the username, password +    verifier, +    @param username, the user ID +    @param password, the user clear text password +    @param params, the SRP parameters for the session +    */ +   public SRPClientSession(String username, char[] password, SRPParameters params) +   { +      this(username, password, params, null); +   } + +   /** Creates a new SRP server session object from the username, password +    verifier, +    @param username, the user ID +    @param password, the user clear text password +    @param params, the SRP parameters for the session +    @param abytes, the random exponent used in the A public key. This must be +      8 bytes in length. +    */ +   public SRPClientSession(String username, char[] password, SRPParameters params, +      byte[] abytes) +   { +      try +      { +         // Initialize the secure random number and message digests +         CryptoUtil.init(); +      } +      catch(NoSuchAlgorithmException e) +      { +      } +      this.params = params; +      this.g = new BigInteger(1, params.g); +      this.N = new BigInteger(1, params.N); +      if( abytes != null ) +      { +         if( 8*abytes.length != A_LEN ) +            throw new IllegalArgumentException("The abytes param must be " +               +(A_LEN/8)+" in length, abytes.length="+abytes.length); +         this.a = new BigInteger(abytes); +      } + +      if( log.isTraceEnabled() ) +         log.trace("g: "+CryptoUtil.tob64(params.g)); +      // Calculate x = H(s | H(U | ':' | password)) +      byte[] xb = CryptoUtil.calculatePasswordHash(username, password, params.s); +      if( log.isTraceEnabled() ) +         log.trace("x: "+CryptoUtil.tob64(xb)); +      this.x = new BigInteger(1, xb); +      this.v = g.modPow(x, N);  // g^x % N +      if( log.isTraceEnabled() ) +         log.trace("v: "+CryptoUtil.tob64(v.toByteArray())); +       +      serverHash = CryptoUtil.newDigest(); +      clientHash = CryptoUtil.newDigest(); +      // H(N) +      byte[] hn = CryptoUtil.newDigest().digest(params.N); +      if( log.isTraceEnabled() ) +         log.trace("H(N): "+CryptoUtil.tob64(hn)); +      // H(g) +      byte[] hg = CryptoUtil.newDigest().digest(params.g); +      if( log.isTraceEnabled() ) +         log.trace("H(g): "+CryptoUtil.tob64(hg)); +      // clientHash = H(N) xor H(g) +      byte[] hxg = CryptoUtil.xor(hn, hg, 20); +      if( log.isTraceEnabled() ) +         log.trace("H(N) xor H(g): "+CryptoUtil.tob64(hxg)); +      clientHash.update(hxg); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g)]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // clientHash = H(N) xor H(g) | H(U) +      clientHash.update(CryptoUtil.newDigest().digest(username.getBytes())); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U)]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // clientHash = H(N) xor H(g) | H(U) | s +      clientHash.update(params.s); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s]: "+CryptoUtil.tob64(tmp.digest())); +      } +      K = null; +   } +    +   /** +    * @returns The exponential residue (parameter A) to be sent to the server. +    */ +   public byte[] exponential() +   { +      byte[] Abytes = null; +      if(A == null) +      { +         /* If the random component of A has not been specified use a random +         number */ +         if( a == null ) +         { +            BigInteger one = BigInteger.ONE; +            do +            { +               a = new BigInteger(A_LEN, CryptoUtil.getPRNG()); +            } while(a.compareTo(one) <= 0); +         } +         A = g.modPow(a, N); +         Abytes = CryptoUtil.trim(A.toByteArray()); +         // clientHash = H(N) xor H(g) | H(U) | A +         clientHash.update(Abytes); +         if( log.isTraceEnabled() ) +         { +            MessageDigest tmp = CryptoUtil.copy(clientHash); +            log.trace("H[H(N) xor H(g) | H(U) | s | A]: "+CryptoUtil.tob64(tmp.digest())); +         } +         // serverHash = A +         serverHash.update(Abytes); +      } +      return Abytes; +   } +    +   /** +    @returns M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) +    @exception NoSuchAlgorithmException thrown if the session key +    MessageDigest algorithm cannot be found. +    */ +   public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException +   { +      // clientHash = H(N) xor H(g) | H(U) | s | A | B +      clientHash.update(Bbytes); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s | A | B]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // Calculate u as the first 32 bits of H(B) +      byte[] hB = CryptoUtil.newDigest().digest(Bbytes); +      byte[] ub = +      {hB[0], hB[1], hB[2], hB[3]}; +      // Calculate S = (B - g^x) ^ (a + u * x) % N +      BigInteger B = new BigInteger(1, Bbytes); +      if( log.isTraceEnabled() ) +         log.trace("B: "+CryptoUtil.tob64(B.toByteArray())); +      if( B.compareTo(v) < 0 ) +         B = B.add(N); +      if( log.isTraceEnabled() ) +         log.trace("B': "+CryptoUtil.tob64(B.toByteArray())); +      if( log.isTraceEnabled() ) +         log.trace("v: "+CryptoUtil.tob64(v.toByteArray())); +      BigInteger u = new BigInteger(1, ub); +      if( log.isTraceEnabled() ) +         log.trace("u: "+CryptoUtil.tob64(u.toByteArray())); +      BigInteger B_v = B.subtract(v); +      if( log.isTraceEnabled() ) +         log.trace("B - v: "+CryptoUtil.tob64(B_v.toByteArray())); +      BigInteger a_ux = a.add(u.multiply(x)); +      if( log.isTraceEnabled() ) +         log.trace("a + u * x: "+CryptoUtil.tob64(a_ux.toByteArray())); +      BigInteger S = B_v.modPow(a_ux, N); +      if( log.isTraceEnabled() ) +         log.trace("S: "+CryptoUtil.tob64(S.toByteArray())); +      // K = SessionHash(S) +      MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); +      K = sessionDigest.digest(S.toByteArray()); +      if( log.isTraceEnabled() ) +         log.trace("K: "+CryptoUtil.tob64(K)); +      // clientHash = H(N) xor H(g) | H(U) | A | B | K +      clientHash.update(K); +      byte[] M1 = clientHash.digest(); +      if( log.isTraceEnabled() ) +         log.trace("M1: H[H(N) xor H(g) | H(U) | s | A | B | K]: "+CryptoUtil.tob64(M1)); +      serverHash.update(M1); +      serverHash.update(K); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(serverHash); +         log.trace("H[A | M1 | K]: "+CryptoUtil.tob64(tmp.digest())); +      } +      return M1; +   } +   /** +    * @param M2 The server's response to the client's challenge +    * @returns True if and only if the server's response was correct. +    */ +   public boolean verify(byte[] M2) +   { +      // M2 = H(A | M1 | K) +      byte[] myM2 = serverHash.digest(); +      boolean valid = Arrays.equals(M2, myM2); +      if( log.isTraceEnabled() ) +      { +         log.trace("verify serverM2: "+CryptoUtil.tob64(M2)); +         log.trace("verify M2: "+CryptoUtil.tob64(myM2)); +      } +      return valid; +   } +    +   /** Returns the negotiated session K, K = SHA_Interleave(S) +    @return the private session K byte[] +    @throws SecurityException - if the current thread does not have an +    getSessionKey SRPPermission. +    */ +   public byte[] getSessionKey() throws SecurityException +   { +      SecurityManager sm = System.getSecurityManager(); +      if( sm != null ) +      { +         SRPPermission p = new SRPPermission("getSessionKey"); +         sm.checkPermission(p); +      } +      return K; +   } +} diff --git a/src/org/jboss/security/srp/SRPConf.java b/src/org/jboss/security/srp/SRPConf.java new file mode 100644 index 0000000..c9b6942 --- /dev/null +++ b/src/org/jboss/security/srp/SRPConf.java @@ -0,0 +1,113 @@ +/* + * 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.srp; + +import java.math.BigInteger; + +import org.jboss.crypto.CryptoUtil; + +/** A port of the libsrp/t_conf.c predefined constants for the N & g parameters +of the SRP algorithm. It contains a collection of "good" primes for N and the +corresponding the corresponding generator g. + +This product includes software developed by Tom Wu and Eugene +Jhong for the SRP Distribution (http://srp.stanford.edu/srp/). + +@author Scott.Stark@jboss.org +@version $Revision: 81038 $ +*/ +public class SRPConf +{ +    /* Master builtin parameter storage object */ +    public static class SRPParams +    { +        String modb64; +        String genb64; +        String comment; +        BigInteger N; +        BigInteger g; +        SRPParams(String modb64, String genb64, String comment) +        { +            this.modb64 = modb64; +            this.genb64 = genb64; +            this.comment = comment; +        } +        public byte[] Nbytes() +        { +            return CryptoUtil.fromb64(modb64); +        } +        public byte[] gbytes() +        { +            return CryptoUtil.fromb64(genb64); +        } +        public BigInteger N() +        { +            if( N == null ) +                N = new BigInteger(1, CryptoUtil.fromb64(modb64)); +            return N; +        } +        public BigInteger g() +        { +            if( g == null ) +                g = new BigInteger(1, CryptoUtil.fromb64(genb64)); +            return g; +        } +        public String getComment() +        { +            return comment; +        } +    } + +    static SRPParams[] pre_params = { +        new SRPParams("3Kn/YYiomHkFkfM1x4kayR125MGkzpLUDy3y14FlTMwYnhZkjrMXnoC2TcFAecNlU5kFzgcpKYUbBOPZFRtyf3", +            "2", null), +        new SRPParams("CbDP.jR6YD6wAj2ByQWxQxQZ7.9J9xkn2.Uqb3zVm16vQyizprhBw9hi80psatZ8k54vwZfiIeEHZVsDnyqeWSSIpWso.wh5GD4OFgdhVI3", +            "2", null), +        new SRPParams("iqJ7nFZ4bGCRjE1F.FXEwL085Zb0kLM2TdHDaVVCdq0cKxvnH/0FLskJTKlDtt6sDl89dc//aEULTVFGtcbA/tDzc.bnFE.DWthQOu2n2JwKjgKfgCR2lZFWXdnWmoOh", +            "2", null), +        new SRPParams("///////////93zgY8MZ2DCJ6Oek0t1pHAG9E28fdp7G22xwcEnER8b5A27cED0JTxvKPiyqwGnimAmfjybyKDq/XDMrjKS95v8MrTc9UViRqJ4BffZes8F//////////", +            "7", "oakley prime 1"), +        new SRPParams("Ewl2hcjiutMd3Fu2lgFnUXWSc67TVyy2vwYCKoS9MLsrdJVT9RgWTCuEqWJrfB6uE3LsE9GkOlaZabS7M29sj5TnzUqOLJMjiwEzArfiLr9WbMRANlF68N5AVLcPWvNx6Zjl3m5Scp0BzJBz9TkgfhzKJZ.WtP3Mv/67I/0wmRZ", +            "2", null), +        new SRPParams("F//////////oG/QeY5emZJ4ncABWDmSqIa2JWYAPynq0Wk.fZiJco9HIWXvZZG4tU.L6RFDEaCRC2iARV9V53TFuJLjRL72HUI5jNPYNdx6z4n2wQOtxMiB/rosz0QtxUuuQ/jQYP.bhfya4NnB7.P9A6PHxEPJWV//////////", +            "5", "oakley prime 2"), +        new SRPParams("3NUKQ2Re4P5BEK0TLg2dX3gETNNNECPoe92h4OVMaDn3Xo/0QdjgG/EvM.hiVV1BdIGklSI14HA38Mpe5k04juR5/EXMU0r1WtsLhNXwKBlf2zEfoOh0zVmDvqInpU695f29Iy7sNW3U5RIogcs740oUp2Kdv5wuITwnIx84cnO.e467/IV1lPnvMCr0pd1dgS0a.RV5eBJr03Q65Xy61R", +            "2", null), +        new SRPParams("dUyyhxav9tgnyIg65wHxkzkb7VIPh4o0lkwfOKiPp4rVJrzLRYVBtb76gKlaO7ef5LYGEw3G.4E0jbMxcYBetDy2YdpiP/3GWJInoBbvYHIRO9uBuxgsFKTKWu7RnR7yTau/IrFTdQ4LY/q.AvoCzMxV0PKvD9Odso/LFIItn8PbTov3VMn/ZEH2SqhtpBUkWtmcIkEflhX/YY/fkBKfBbe27/zUaKUUZEUYZ2H2nlCL60.JIPeZJSzsu/xHDVcx", +            "2", null), +        new SRPParams("2iQzj1CagQc/5ctbuJYLWlhtAsPHc7xWVyCPAKFRLWKADpASkqe9djWPFWTNTdeJtL8nAhImCn3Sr/IAdQ1FrGw0WvQUstPx3FO9KNcXOwisOQ1VlL.gheAHYfbYyBaxXL.NcJx9TUwgWDT0hRzFzqSrdGGTN3FgSTA1v4QnHtEygNj3eZ.u0MThqWUaDiP87nqha7XnT66bkTCkQ8.7T8L4KZjIImrNrUftedTTBi.WCi.zlrBxDuOM0da0JbUkQlXqvp0yvJAPpC11nxmmZOAbQOywZGmu9nhZNuwTlxjfIro0FOdthaDTuZRL9VL7MRPUDo/DQEyW.d4H.UIlzp", +            "2", null), +    }; + +    public int getPredefinedCount() +    { +        return pre_params.length; +    } +    public static SRPParams getPredefinedParams(int n) +    { +        return pre_params[n]; +    } +    public static SRPParams getDefaultParams() +    { +        return pre_params[6]; +    } +} diff --git a/src/org/jboss/security/srp/SRPParameters.java b/src/org/jboss/security/srp/SRPParameters.java new file mode 100644 index 0000000..43e2dad --- /dev/null +++ b/src/org/jboss/security/srp/SRPParameters.java @@ -0,0 +1,150 @@ +/* + * 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.srp; + +import java.io.Serializable; +import java.util.Arrays; + +import org.jboss.crypto.CryptoUtil; + +/** The RFC2945 algorithm session parameters that the client and server +agree to use. In addition to the base RFC2945 parameters, one can choose an +alternate hash algorithm for the private session key. + +@author Scott.Stark@jboss.org +@version $Revision: 81038 $ +*/ +public class SRPParameters implements Cloneable, Serializable +{ +   /** The serial version ID. +    * @since 1.2.4.1 +    */ +   private static final long serialVersionUID = 6438772808805276693L; + +   /** The algorithm safe-prime modulus */ +   public final byte[] N; +   /** The algorithm primitive generator */ +   public final byte[] g; +   /** The random password salt originally used to verify the password */ +   public final byte[] s; +   /** The algorithm to hash the session key to produce K. To be consistent +    with the RFC2945 description this must be SHA_Interleave as implemented +    by the JBossSX security provider. For compatibility with earlier JBossSX +    SRP releases the algorithm must be SHA_ReverseInterleave. This name is +    passed to java.security.MessageDigest.getInstance(). */ +   public final String hashAlgorithm; +   /** The algorithm to use for any encryption of data. +    */ +   public final String cipherAlgorithm; +   /** The cipher intialization vector bytes +    */ +   public byte[] cipherIV; + +   /** Creates a new instance of SRPParameters */ +   public SRPParameters(byte[] N, byte[] g, byte[] s) +   { +      this(N, g, s, "SHA_Interleave", null); +   } +   public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm) +   { +      this(N, g, s, hashAlgorithm, null); +   } +   public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm, +      String cipherAlgorithm) +   { +      this(N, g, s, hashAlgorithm, cipherAlgorithm, null); +   } +   public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm, +      String cipherAlgorithm, byte[] cipherIV) +   { +      this.N = N; +      this.g = g; +      this.s = s; +      if( hashAlgorithm == null ) +         hashAlgorithm = "SHA_Interleave"; +      this.hashAlgorithm = hashAlgorithm; +      this.cipherAlgorithm = cipherAlgorithm; +      this.cipherIV = cipherIV; +   } + +   public Object clone() +   { +      Object clone = null; +      try +      { +          clone = super.clone(); +      } +      catch(CloneNotSupportedException e) +      { +      } +      return clone; +   } + +   public int hashCode() +   { +      int hashCode = hashAlgorithm.hashCode(); +      for(int i = 0; i < N.length; i ++) +         hashCode += N[i]; +      for(int i = 0; i < g.length; i ++) +         hashCode += g[i]; +      for(int i = 0; i < s.length; i ++) +         hashCode += s[i]; +      return hashCode; +   } + +   public boolean equals(Object obj) +   { +      boolean equals = false; +      if( obj instanceof SRPParameters ) +      { +         SRPParameters p = (SRPParameters) obj; +         equals = hashAlgorithm.equals(p.hashAlgorithm); +         if( equals == true ) +            equals = Arrays.equals(N, p.N); +         if( equals == true ) +            equals = Arrays.equals(g, p.g); +         if( equals == true ) +            equals = Arrays.equals(s, p.s); +      } +      return equals; +   } + +   public String toString() +   { +      StringBuffer tmp = new StringBuffer(super.toString()); +      tmp.append('{'); +      tmp.append("N: "); +      tmp.append(CryptoUtil.encodeBase64(N)); +      tmp.append("|g: "); +      tmp.append(CryptoUtil.encodeBase64(g)); +      tmp.append("|s: "); +      tmp.append(CryptoUtil.encodeBase64(s)); +      tmp.append("|hashAlgorithm: "); +      tmp.append(hashAlgorithm); +      tmp.append("|cipherAlgorithm: "); +      tmp.append(cipherAlgorithm); +      tmp.append("|cipherIV: "); +      tmp.append(cipherIV); +      tmp.append('}'); +      return tmp.toString(); +   } +} diff --git a/src/org/jboss/security/srp/SRPPermission.java b/src/org/jboss/security/srp/SRPPermission.java new file mode 100644 index 0000000..d1a77d6 --- /dev/null +++ b/src/org/jboss/security/srp/SRPPermission.java @@ -0,0 +1,66 @@ +/* + * 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.srp; + +import java.security.BasicPermission; + +/** A custom permission class for protecting access to sensitive SRP information +like the private session key and private key. + +The following table lists all the possible SRPPermission target names, +and for each provides a description of what the permission allows +and a discussion of the risks of granting code the permission. +<table border=1 cellpadding=5> +    <tr> +        <th>Permission Target Name</th> +        <th>What the Permission Allows</th> +        <th>Risks of Allowing this Permission</th> +    </tr> + +    <tr> +        <td>getSessionKey</td> +        <td>Access the private SRP session key</td> +        <td>This provides access the the private session key that results from +the SRP negiotation. Access to this key will allow one to encrypt/decrypt msgs +that have been encrypted with the session key. +        </td> +    </tr> + +</table> + +@author Scott.Stark@jboss.org +@version $Revision: 81038 $ +*/ +public class SRPPermission extends BasicPermission +{ + +    /** Creates new SRPPermission */ +    public SRPPermission(String name) +    { +        super(name); +    } +    public SRPPermission(String name, String actions) +    { +        super(name, actions); +    } + +} diff --git a/src/org/jboss/security/srp/SRPServerListener.java b/src/org/jboss/security/srp/SRPServerListener.java new file mode 100644 index 0000000..a9e22cb --- /dev/null +++ b/src/org/jboss/security/srp/SRPServerListener.java @@ -0,0 +1,42 @@ +/* + * 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.srp; + +/** A callback interface for SRP session events. + +@author  Scott.Stark@jboss.org +@version $Revision: 81038 $ +*/ +public interface SRPServerListener +{ +   /** Called when a user has successfully completed the SRP handshake and any auxillary +    * challenge verification. +    * @param key, the {username, sessionID} pair +    * @param session, the server SRP session information +    */ +   public void verifiedUser(SRPSessionKey key, SRPServerSession session); +   /** Called when a user requests that a session be closed +    * +    * @param key, the {username, sessionID} pair +    */ +   public void closedUserSession(SRPSessionKey key); +} diff --git a/src/org/jboss/security/srp/SRPServerSession.java b/src/org/jboss/security/srp/SRPServerSession.java new file mode 100644 index 0000000..11dc6d4 --- /dev/null +++ b/src/org/jboss/security/srp/SRPServerSession.java @@ -0,0 +1,285 @@ +/* + * 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.srp; + +import java.io.Serializable; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import org.jboss.logging.Logger; +import org.jboss.crypto.CryptoUtil; + +/** The server side logic to the SRP protocol. The class is the server side + equivalent of the SRPClientSession object. An implementation of + SRPServerInterface creates an SRPServerSession on the start of a login + session. +  + The client side algorithm using these classes consists of: +  + 1. Get server, SRPServerInterface server = (SRPServerInterface) Naming.lookup(...); + 2. Get SRP parameters, SRPParameters params = server.getSRPParameters(username); + 3. Create a client session, SRPClientSession client = new SRPClientSession(username, password, params); + 4. Exchange public keys, byte[] A = client.exponential(); + byte[] B = server.init(username, A); + 5. Exchange challenges, byte[] M1 = client.response(B); + byte[] M2 = server.verify(username, M1); + 6. Verify the server response, if( client.verify(M2) == false ) + throw new SecurityException("Failed to validate server reply"); + 7. Validation complete +  + Note that these steps are stateful. They must be performed in order and a + step cannot be repeated to update the session state. +  + This product uses the 'Secure Remote Password' cryptographic + authentication system developed by Tom Wu (tjw@CS.Stanford.EDU). +  + @author Scott.Stark@jboss.org + @version $Revision: 81038 $ + */ +public class SRPServerSession implements Serializable +{ +   /** The serial version ID +    @since 1.6 +    */ +   static final long serialVersionUID = -2448005747721323704L; +   private static int B_LEN = 64; // 64 bits for 'b' +   private static Logger log = Logger.getLogger(SRPServerSession.class); + +   private SRPParameters params; +   private BigInteger N; +   private BigInteger g; +   private BigInteger v; +   private BigInteger b; +   private BigInteger B; +   private byte[] K; +   /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ +   private transient MessageDigest clientHash; +   private byte[] M1; +   /** The M2 = H(A | M | K) hash */ +   private transient MessageDigest serverHash; +   private byte[] M2; +    +   /** Creates a new SRP server session object from the username, password +    verifier, and session parameters. +    @param username, the user ID +    @param vb, the password verifier byte sequence +    @param params, the SRP parameters for the session +    */ +   public SRPServerSession(String username, byte[] vb, SRPParameters params) +   { +      this.params = params; +      this.v = new BigInteger(1, vb); +      this.g = new BigInteger(1, params.g); +      this.N = new BigInteger(1, params.N); +      if( log.isTraceEnabled() ) +         log.trace("g: "+CryptoUtil.tob64(params.g)); +      if( log.isTraceEnabled() ) +         log.trace("v: "+CryptoUtil.tob64(vb)); +      serverHash = CryptoUtil.newDigest(); +      clientHash = CryptoUtil.newDigest(); +      // H(N) +      byte[] hn = CryptoUtil.newDigest().digest(params.N); +      if( log.isTraceEnabled() ) +         log.trace("H(N): "+CryptoUtil.tob64(hn)); +      // H(g) +      byte[] hg = CryptoUtil.newDigest().digest(params.g); +      if( log.isTraceEnabled() ) +         log.trace("H(g): "+CryptoUtil.tob64(hg)); +      // clientHash = H(N) xor H(g) +      byte[] hxg = CryptoUtil.xor(hn, hg, 20); +      if( log.isTraceEnabled() ) +         log.trace("H(N) xor H(g): "+CryptoUtil.tob64(hxg)); +      clientHash.update(hxg); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g)]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // clientHash = H(N) xor H(g) | H(U) +      clientHash.update(CryptoUtil.newDigest().digest(username.getBytes())); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U)]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // clientHash = H(N) xor H(g) | H(U) | s +      clientHash.update(params.s); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s]: "+CryptoUtil.tob64(tmp.digest())); +      } +      K = null; +   } +    +   /** +    * @returns The user's password salt +    */ +   public SRPParameters getParameters() +   { +      return params; +   } +    +   /** +    * @returns The exponential residue (parameter B) to be sent to the +    *          client. +    */ +   public byte[] exponential() +   { +      if(B == null) +      { +         BigInteger one = BigInteger.valueOf(1); +         do +         { +            b = new BigInteger(B_LEN, CryptoUtil.getPRNG()); +         } while(b.compareTo(one) <= 0); +         B = v.add(g.modPow(b, N)); +         if(B.compareTo(N) >= 0) +            B = B.subtract(N); +      } +      return CryptoUtil.trim(B.toByteArray()); +   } +    +   /** +   @param ab The client's exponential (parameter A). +   @returns The secret shared session K between client and server +    @exception NoSuchAlgorithmException thrown if the session key +    MessageDigest algorithm cannot be found. +    */ +   public void buildSessionKey(byte[] ab) throws NoSuchAlgorithmException +   { +      if( log.isTraceEnabled() ) +         log.trace("A: "+CryptoUtil.tob64(ab)); +      byte[] nb = CryptoUtil.trim(B.toByteArray()); +      // clientHash = H(N) xor H(g) | H(U) | s | A +      clientHash.update(ab); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s | A]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // clientHash = H(N) xor H(g) | H(U) | A | B +      clientHash.update(nb); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s | A | B]: "+CryptoUtil.tob64(tmp.digest())); +      } +      // serverHash = A +      serverHash.update(ab); +      // Calculate u as the first 32 bits of H(B) +      byte[] hB = CryptoUtil.newDigest().digest(nb); +      byte[] ub = +      {hB[0], hB[1], hB[2], hB[3]}; +      // Calculate S = (A * v^u) ^ b % N +      BigInteger A = new BigInteger(1, ab); +      if( log.isTraceEnabled() ) +         log.trace("A: "+CryptoUtil.tob64(A.toByteArray())); +      if( log.isTraceEnabled() ) +         log.trace("B: "+CryptoUtil.tob64(B.toByteArray())); +      if( log.isTraceEnabled() ) +         log.trace("v: "+CryptoUtil.tob64(v.toByteArray())); +      BigInteger u = new BigInteger(1, ub); +      if( log.isTraceEnabled() ) +         log.trace("u: "+CryptoUtil.tob64(u.toByteArray())); +      BigInteger A_v2u = A.multiply(v.modPow(u, N)).mod(N); +      if( log.isTraceEnabled() ) +         log.trace("A * v^u: "+CryptoUtil.tob64(A_v2u.toByteArray())); +      BigInteger S = A_v2u.modPow(b, N); +      if( log.isTraceEnabled() ) +         log.trace("S: "+CryptoUtil.tob64(S.toByteArray())); +      // K = SessionHash(S) +      MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); +      K = sessionDigest.digest(S.toByteArray()); +      if( log.isTraceEnabled() ) +         log.trace("K: "+CryptoUtil.tob64(K)); +      // clientHash = H(N) xor H(g) | H(U) | A | B | K +      clientHash.update(K); +      if( log.isTraceEnabled() ) +      { +         MessageDigest tmp = CryptoUtil.copy(clientHash); +         log.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: "+CryptoUtil.tob64(tmp.digest())); +      } +   } +    +   /** Returns the negotiated session K, K = SessionHash(S) +    @return the private session K byte[] +    @throws SecurityException - if the current thread does not have an +    getSessionKey SRPPermission. +    */ +   public byte[] getSessionKey() throws SecurityException +   { +      SecurityManager sm = System.getSecurityManager(); +      if( sm != null ) +      { +         SRPPermission p = new SRPPermission("getSessionKey"); +         sm.checkPermission(p); +      } +      return K; +   } + +   /** +    @returns M2 = H(A | M | K) +    */ +   public byte[] getServerResponse() +   { +      if( M2 == null ) +         M2 = serverHash.digest(); +      return M2; +   } +   public byte[] getClientResponse() +   { +      return M1; +   } +    +   /** +    * @param resp The client's response to the server's challenge +    * @returns True if and only if the client's response was correct. +    */ +   public boolean verify(byte[] clientM1) +   { +      boolean valid = false; +      // M1 = H(H(N) xor H(g) | H(U) | A | B | K) +      M1 = clientHash.digest(); +      if( log.isTraceEnabled() ) +      { +         log.trace("verify M1: "+CryptoUtil.tob64(M1)); +         log.trace("verify clientM1: "+CryptoUtil.tob64(clientM1)); +      } +      if( Arrays.equals(clientM1, M1) ) +      { +         // serverHash = A | M +         serverHash.update(M1); +         // serverHash = A | M | K +         serverHash.update(K); +         if( log.isTraceEnabled() ) +         { +            MessageDigest tmp = CryptoUtil.copy(serverHash); +            log.trace("H(A | M1 | K)"+CryptoUtil.tob64(tmp.digest())); +         } +         valid = true; +      } +      return valid; +   } +} diff --git a/src/org/jboss/security/srp/SRPSessionKey.java b/src/org/jboss/security/srp/SRPSessionKey.java new file mode 100644 index 0000000..e0f2131 --- /dev/null +++ b/src/org/jboss/security/srp/SRPSessionKey.java @@ -0,0 +1,78 @@ +/* + * 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.srp; + +import java.io.Serializable; + +/* An encapsulation of an SRP username and session id. + * @author Scott.Stark@jboss.org + * @version $Revision: 81038 $ + */ +public class SRPSessionKey implements Serializable +{ +   private static final long serialVersionUID = -7783783206948014409L; +   public static final Integer NO_SESSION_ID = new Integer(0); +   private String username; +   private int sessionID; + +   public SRPSessionKey(String username) +   { +      this(username, NO_SESSION_ID); +   } +   public SRPSessionKey(String username, int sessionID) +   { +      this.username = username; +      this.sessionID = sessionID; +   } +   public SRPSessionKey(String username, Integer sessionID) +   { +      this.username = username; +      if( sessionID != null ) +         this.sessionID = sessionID.intValue(); +   } + +   public boolean equals(Object obj) +   { +      SRPSessionKey key = (SRPSessionKey) obj; +      return this.username.equals(key.username) && this.sessionID == key.sessionID; +   } + +   public int hashCode() +   { +      return this.username.hashCode() + this.sessionID; +   } + +   public int getSessionID() +   { +      return sessionID; +   } + +   public String getUsername() +   { +      return username; +   } + +   public String toString() +   { +      return "{username="+username+", sessionID="+sessionID+"}"; +   } +} diff --git a/src/org/jboss/security/srp/SRPVerifierStore.java b/src/org/jboss/security/srp/SRPVerifierStore.java new file mode 100644 index 0000000..b4487dd --- /dev/null +++ b/src/org/jboss/security/srp/SRPVerifierStore.java @@ -0,0 +1,115 @@ +/* + * 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.srp; + +import java.io.IOException; +import java.io.Serializable; +import java.io.ObjectStreamField; +import java.security.KeyException; + +/** An interface describing the requirements of a password verifier store. +This is an abstraction that allows the <username, verifier, salt> information +needed by the server to be plugged in from various sources. E.g., LDAP +servers, databases, files, etc. + + @author Scott.Stark@jboss.org + @version $Revision: 81038 $ +*/ +public interface SRPVerifierStore +{ +   public static class VerifierInfo implements Serializable +   { +      /** The serial version UID @since 1.2.4.1 */ +      private static final long serialVersionUID = 7420301687504271098L; +      private static final ObjectStreamField[] serialPersistentFields = { +         new ObjectStreamField("username", String.class), +         new ObjectStreamField("verifier", byte[].class), +         new ObjectStreamField("salt", byte[].class), +         new ObjectStreamField("g", byte[].class), +         new ObjectStreamField("N", byte[].class), +         new ObjectStreamField("hashAlgorithm", String.class), +         new ObjectStreamField("cipherAlgorithm", String.class), +         new ObjectStreamField("cipherIV", byte[].class) +      }; + +      /** The username the information applies to. Perhaps redundant but it +       * makes the object self contained. +       * @serialField username String username +       */ +      public String username; +      /** The SRP password verifier hash +       * @serialField verifier byte[] password verifier +       */ +      public byte[] verifier; +      /** The random password salt originally used to verify the password +       * @serialField salt originally used to verify the password +       */ +      public byte[] salt; +      /** The SRP algorithm primitive generator +       * @serialField g primitive generator +       */ +      public byte[] g; +      /** The algorithm safe-prime modulus +       * @serialField N safe-prime modulus +       */ +      public byte[] N; +      /** The algorithm to hash the session key to produce K. To be consistent +       with the RFC2945 description this must be SHA_Interleave as implemented +       by the JBossSX security provider. For compatibility with earlier JBossSX +       SRP releases the algorithm must be SHA_ReverseInterleave. This name is +       passed to java.security.MessageDigest.getInstance(). +       * @serialField hashAlgorithm algorithm to hash the session key +       * @since 1.2.4.2 +       */ +      public String hashAlgorithm; +      /** The algorithm to use for any encryption of data. +       * @serialField cipherAlgorithm algorithm to use for any encryption +       * @since 1.2.4.2 +       */ +      public String cipherAlgorithm; +      /** The initialization vector to use for any encryption of data. +       * @serialField cipherIV initialization vector to use for any encryption +       * @since 1.6 +       */ +      public byte[] cipherIV; +   } + +    /** Get the indicated user's password verifier information. +     */ +    public VerifierInfo getUserVerifier(String username) +      throws KeyException, IOException; +    /** Set the indicated users' password verifier information. This is equivalent +     to changing a user's password and should generally invalidate any existing +     SRP sessions and caches. +     */ +    public void setUserVerifier(String username, VerifierInfo info) +      throws IOException; + +   /** Verify an optional auxillary challenge sent from the client to the server. The +    * auxChallenge object will have been decrypted if it was sent encrypted from the +    * client. An example of a auxillary challenge would be the validation of a hardware +    * token (SafeWord, SecureID, iButton) that the server validates to further strengthen +    * the SRP password exchange. +    */ +   public void verifyUserChallenge(String username, Object auxChallenge) +         throws SecurityException; +} diff --git a/src/org/jboss/security/srp/SerialObjectStore.java b/src/org/jboss/security/srp/SerialObjectStore.java new file mode 100644 index 0000000..3170488 --- /dev/null +++ b/src/org/jboss/security/srp/SerialObjectStore.java @@ -0,0 +1,216 @@ +/* + * 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.srp; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.KeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.jboss.logging.Logger; +import org.jboss.crypto.CryptoUtil; +import org.jboss.security.srp.SRPConf; +import org.jboss.security.srp.SRPVerifierStore; +import org.jboss.security.srp.SRPVerifierStore.VerifierInfo; + +/** A simple implementation of the SRPVerifierStore that uses a +file store made up of VerifierInfo serialized objects. Users and +be added or removed using the addUser and delUser methods. User passwords +are never stored in plaintext either in memory or in the serialized file. +Note that usernames and passwords are logged when a user is added +via the addUser operation. This is a development class and its use in +a production environment is not advised. + +@see #addUser(String, String) +@see #delUser(String) + +@author Scott.Stark@jboss.org +@version $Revision: 81038 $ +*/ +public class SerialObjectStore implements SRPVerifierStore +{ +    private static Logger log = Logger.getLogger(SerialObjectStore.class); +    private Map infoMap; +    private BigInteger g; +    private BigInteger N; + +   /** Create an in memory store and load any VerifierInfo found in +        ./SerialObjectStore.ser if it exists. +    */ +    public SerialObjectStore() throws IOException +    { +        this(null); +    } +    /** Create an in memory store and load any VerifierInfo found in +        the storeFile archive if it exists. +    */ +    public SerialObjectStore(File storeFile) throws IOException +    { +        if( storeFile == null ) +            storeFile = new File("SerialObjectStore.ser"); +        if( storeFile.exists() == true ) +        { +            FileInputStream fis = new FileInputStream(storeFile); +            ObjectInputStream ois = new ObjectInputStream(fis); +            try +            { +                infoMap = (Map) ois.readObject(); +            } +            catch(ClassNotFoundException e) +            { +            } +            ois.close(); +            fis.close(); +        } +        else +        { +            infoMap = Collections.synchronizedMap(new HashMap()); +        } + +        try +        { +           CryptoUtil.init(); +        } +        catch(NoSuchAlgorithmException e) +        { +            e.printStackTrace(); +            throw new IOException("Failed to initialzed security utils: "+e.getMessage()); +        } +        N = SRPConf.getDefaultParams().N(); +        g = SRPConf.getDefaultParams().g(); +        log.trace("N: "+CryptoUtil.tob64(N.toByteArray())); +        log.trace("g: "+CryptoUtil.tob64(g.toByteArray())); +        byte[] hn = CryptoUtil.newDigest().digest(N.toByteArray()); +        log.trace("H(N): "+CryptoUtil.tob64(hn)); +        byte[] hg = CryptoUtil.newDigest().digest(g.toByteArray()); +        log.trace("H(g): "+CryptoUtil.tob64(hg)); +    } + +// --- Begin SRPVerifierStore interface methods +    public VerifierInfo getUserVerifier(String username) throws KeyException, IOException +    { +        VerifierInfo info = null; +        if( infoMap != null ) +            info = (VerifierInfo) infoMap.get(username); +        if( info == null ) +            throw new KeyException("username: "+username+" not found"); +        return info; +    } +    public void setUserVerifier(String username, VerifierInfo info) +    { +        infoMap.put(username, info); +    } + +   public void verifyUserChallenge(String username, Object auxChallenge) +         throws SecurityException +   { +      throw new SecurityException("verifyUserChallenge not supported"); +   } +// --- End SRPVerifierStore interface methods + +    /** Save the current in memory map of VerifierInfo to the indicated +        storeFile by simply serializing the map to the file. +    */ +    public void save(File storeFile) throws IOException +    { +        FileOutputStream fos = new FileOutputStream(storeFile); +        ObjectOutputStream oos = new ObjectOutputStream(fos); +        synchronized( infoMap ) +        { +            oos.writeObject(infoMap); +        } +        oos.close(); +        fos.close(); +    } + +    public void addUser(String username, String password) +    { +        log.trace("addUser, username='"+username+"', password='"+password+"'"); +        VerifierInfo info = new VerifierInfo(); +        info.username = username; +        /* +        long r = Util.nextLong(); +        String rs = Long.toHexString(r); +         */ +        String rs = "123456"; +        info.salt = rs.getBytes(); +        try +        { +           char[] pass = password.toCharArray(); +           info.verifier = CryptoUtil.calculateVerifier(username, pass, +               info.salt, N, g); +           info.g = g.toByteArray(); +           info.N = N.toByteArray(); +           if( log.isTraceEnabled() ) +           { +               log.trace("N: "+CryptoUtil.tob64(info.N)); +               log.trace("g: "+CryptoUtil.tob64(info.g)); +               log.trace("s: "+CryptoUtil.tob64(info.salt)); +               byte[] xb = CryptoUtil.calculatePasswordHash(username, pass, info.salt); +               log.trace("x: "+CryptoUtil.tob64(xb)); +               log.trace("v: "+CryptoUtil.tob64(info.verifier)); +               byte[] hn = CryptoUtil.newDigest().digest(info.N); +               log.trace("H(N): "+CryptoUtil.tob64(hn)); +               byte[] hg = CryptoUtil.newDigest().digest(info.g); +               log.trace("H(g): "+CryptoUtil.tob64(hg)); +           } +        } +        catch(Throwable t) +        { +           log.error("Failed to calculate verifier", t); +           return; +        } + +        setUserVerifier(username, info); +    } +    public void delUser(String username) +    { +        infoMap.remove(username); +    } + +    public static void main(String[] args) throws IOException +    { +        File storeFile = new File("SerialObjectStore.ser"); +        SerialObjectStore store = new SerialObjectStore(); + +        for(int a = 0; a < args.length; a ++) +        { +            if( args[a].startsWith("-a") ) +            { +                store.addUser(args[a+1], args[a+2]); +            } +            else if( args[a].startsWith("-d") ) +            { +                store.delUser(args[a+1]); +            } +        } +        store.save(storeFile); +    } +} diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index e2af08e..591bdc9 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -171,9 +171,12 @@ public class ProviderAPI extends IntentService {  		srp_client.init(n, ConfigHelper.g, new SHA256Digest(), new SecureRandom());  		BigInteger salt = BigInteger.probablePrime(1024, null); -		BigInteger clientA = srp_client.generateClientCredentials(salt.toByteArray(), username.getBytes(), password.getBytes()); + +		BigInteger clientA = srp_client.generateClientCredentials(salt.toString(16).getBytes(), username.getBytes(), password.getBytes()); +  		try {  			BigInteger serverB = sendAToSRPServer(authentication_server, username, clientA); +  			if(serverB == BigInteger.ZERO)  				return false; // TODO Show error: error trying to start authentication with provider @@ -241,7 +244,7 @@ public class ProviderAPI extends IntentService {  	}  	public BigInteger generateM1(BigInteger K, BigInteger salt, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { -		String digest_of_N_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.NG_1024.getBytes())).toString(16); +		String digest_of_N_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(hex2ascii(ConfigHelper.NG_1024).getBytes())).toString(16);  		String digest_of_G_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toString(16).getBytes())).toString(16); @@ -297,7 +300,11 @@ public class ProviderAPI extends IntentService {  	private String hexXor(String a, String b) {  	    String str = "";  	    for (int i = 0; i < a.length(); i += 2) { -	      int xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); +	    	int xor = 0; +	    	if(a.length() > i + 2) +	    		xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); +	    	else +	    		xor = Integer.parseInt(a.substring(i, 1 + i), 16) ^ Integer.parseInt(b.substring(i, 1 + i), 16);  	      String xor_string = String.valueOf(Integer.valueOf(String.valueOf(xor), 16));  	      str += (xor_string.length() == 1) ? ("0" + xor) : xor_string;  	    } @@ -328,6 +335,16 @@ public class ProviderAPI extends IntentService {       }       return buffer.toString();  } +	 +	private String hex2ascii(String hex) { +		StringBuilder output = new StringBuilder(); +	    for (int i = 0; i < hex.length(); i+=2) { +	        String str = hex.substring(i, i+2); +	        output.append((char)Integer.parseInt(str, 16)); +	    } +	    String debug = output.toString(); +	    return output.toString(); +	}  	private BigInteger sendM1ToSRPServer(String server_url, String username, BigInteger m1) throws ClientProtocolException, IOException, JSONException {  		DefaultHttpClient client = new LeapHttpClient(getApplicationContext());  | 
