User: stark   
  Date: 01/03/06 00:35:32

  Added:       src/main/org/jboss/security/srp PkgCategory.java
                        SRPClientSession.java SRPConf.java
                        SRPRemoteServer.java SRPRemoteServerInterface.java
                        SRPServerInterface.java SRPServerSession.java
                        SRPVerifierStore.java SerialObjectStore.java
                        TracePriority.java
  Log:
  Added srp package that was missed. Updated AbstractServerLoginModule to
  support password stacking. Updated RolesLoginModule to use existing
  Groups. Updated JaasSecurityManager to operate correctly as a role-mapping
  only manager when so configured.
  
  Revision  Changes    Path
  1.1                  jbosssx/src/main/org/jboss/security/srp/PkgCategory.java
  
  Index: PkgCategory.java
  ===================================================================
  package org.jboss.security.srp;
  
  import org.apache.log4j.Category;
  
  /** 
  
  @see org.apache.log4j.Category
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class PkgCategory
  {
        static Category instance;
  
      static
      {
          instance = Category.getInstance("org.jboss.security.srp");
      }
  
        private PkgCategory()
        {
        }
  
  // --- Begin convience methods
        public static boolean isTraceEnabled()
        {
                return instance.isEnabledFor(TracePriority.TRACE);
        }
        public static boolean isDebugEnabled()
        {
                return instance.isDebugEnabled();
        }
  
        public static void trace(Object msg)
        {
          instance.log(TracePriority.TRACE, msg);
        }
        public static void debug(Object msg)
        {
                instance.debug(msg);
        }
        public static void info(Object msg)
        {
                instance.info(msg);
        }
        public static void warn(Object msg)
        {
                instance.warn(msg);
        }
        public static void warn(Object msg, Throwable t)
        {
                instance.warn(msg, t);
        }
        public static void error(Object msg)
        {
                instance.error(msg);
        }
        public static void error(Object msg, Throwable t)
        {
                instance.error(msg, t);
        }
        public static void fatal(Object msg)
        {
                instance.fatal(msg);
        }
        public static void fatal(Object msg, Throwable t)
        {
                instance.fatal(msg, t);
        }
  // --- End convience methods
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPClientSession.java
  
  Index: SRPClientSession.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.IOException;
  import java.math.BigInteger;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Arrays;
  
  import org.jboss.security.Util;
  
  /** The client side logic to the SRP protocol. The class was derived from
  the security.srp.SRPClient class. 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.s, params.N, params.g);
  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 ([EMAIL PROTECTED]).
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SRPClientSession
  {
      private BigInteger N;
      private BigInteger g;
      private BigInteger x;
      private BigInteger v;
      private byte[] s;
      private BigInteger a;
      private BigInteger A;
      private byte[] key;
      /** 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 password verifier byte sequence
      @param s, the password salt byte sequence
      @param nb, the algorithm safe-prime modulus byte sequence
      @param gb, the algorithm primitive generator byte sequence
      */
      public SRPClientSession(String username, String password, byte[] s, byte[] nb, 
byte[] gb)
      {
          try
          {
              Util.init();
          }
          catch(NoSuchAlgorithmException e)
          {
          }
          this.s = s;
          this.g = new BigInteger(1, gb);
          this.N = new BigInteger(1, nb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("g: "+Util.tob64(gb));
          // Calculate x = H(s | H(U | ':' | password))
          byte[] xb = Util.calculatePasswordHash(username, password, s, N, g);
          this.x = new BigInteger(1, xb);
          v = g.modPow(x, N);  // g^x % N
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("v: "+Util.tob64(v.toByteArray()));
  
          serverHash = Util.newDigest();
          clientHash = Util.newDigest();
          // H(N)
          byte[] hn = Util.newDigest().digest(nb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(N): "+Util.tob64(hn));
          // H(g)
          byte[] hg = Util.newDigest().digest(gb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(g): "+Util.tob64(hg));
          // clientHash = H(N) xor H(g)
          byte[] hxg = Util.xor(hn, hg, 20);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(N) xor H(g): "+Util.tob64(hxg));
          clientHash.update(hxg);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g)]: "+Util.tob64(tmp.digest()));
          }
          // clientHash = H(N) xor H(g) | H(U)
          clientHash.update(Util.newDigest().digest(username.getBytes()));
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest()));
          }
          // clientHash = H(N) xor H(g) | H(U) | s
          clientHash.update(s);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s]: 
"+Util.tob64(tmp.digest()));
          }
          key = null;
      }
  
      /**
      * @returns The exponential residue (parameter A) to be sent to the server.
      */
      public byte[] exponential()
      {
          byte[] Abytes = null;
          if(A == null)
          {
              BigInteger one = BigInteger.ONE;
              do
              {
                  a = new BigInteger(A_LEN, Util.getPRNG());
              } while(a.compareTo(one) <= 0);
              A = g.modPow(a, N);
              Abytes = Util.trim(A.toByteArray());
              // clientHash = H(N) xor H(g) | H(U) | A
              clientHash.update(Abytes);
              if( PkgCategory.isTraceEnabled() )
              {
                  MessageDigest tmp = Util.copy(clientHash);
                  PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A]: 
"+Util.tob64(tmp.digest()));
              }
              // serverHash = A
              serverHash.update(Abytes);
          }
          return Abytes;
      }
  
      /**
      @returns M1 = H(H(N) xor H(g) | H(U) | s | A | B | K)
      */
      public byte[] response(byte[] Bbytes)
      {
          // clientHash = H(N) xor H(g) | H(U) | s | A | B
          clientHash.update(Bbytes);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A | B]: 
"+Util.tob64(tmp.digest()));
          }
          // Calculate u as the first 32 bits of H(B)
          byte[] hB = Util.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( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("B: "+Util.tob64(B.toByteArray()));
          if( B.compareTo(v) < 0 )
              B = B.add(N);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("B': "+Util.tob64(B.toByteArray()));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("v: "+Util.tob64(v.toByteArray()));
          BigInteger u = new BigInteger(1, ub);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("u: "+Util.tob64(u.toByteArray()));
          BigInteger B_v = B.subtract(v);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("B - v: "+Util.tob64(B_v.toByteArray()));
          BigInteger a_ux = a.add(u.multiply(x));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("a + u * x: "+Util.tob64(a_ux.toByteArray()));
          BigInteger S = B_v.modPow(a_ux, N);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("S: "+Util.tob64(S.toByteArray()));
          // K = SHA_Interleave(S)
          key = Util.sessionKeyHash(Util.trim(S.toByteArray()));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("K: "+Util.tob64(key));
          // clientHash = H(N) xor H(g) | H(U) | A | B | K
          clientHash.update(key);
          byte[] M1 = clientHash.digest();
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: 
"+Util.tob64(M1));
          serverHash.update(M1);
          serverHash.update(key);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[A | M | K]: "+Util.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( PkgCategory.isTraceEnabled() )
          {
              PkgCategory.trace("verify serverM2: "+Util.tob64(M2));
              PkgCategory.trace("verify M2: "+Util.tob64(myM2));
          }
          return valid;
      }
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPConf.java
  
  Index: SRPConf.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.math.BigInteger;
  
  import org.jboss.security.Util;
  
  /** A port of the libsrp/t_conf.c predefined constants for the N & g parameters
  of the SRP algorithm.
  
  This product includes software developed by Tom Wu and Eugene
  Jhong for the SRP Distribution (http://srp.stanford.edu/srp/).
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  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 Util.fromb64(modb64);
          }
          public byte[] gbytes()
          {
              return Util.fromb64(genb64);
          }
          public BigInteger N()
          {
              if( N == null )
                  N = new BigInteger(1, Util.fromb64(modb64));
              return N;
          }
          public BigInteger g()
          {
              if( g == null )
                  g = new BigInteger(1, Util.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];
      }
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPRemoteServer.java
  
  Index: SRPRemoteServer.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.IOException;
  import java.rmi.RemoteException;
  import java.rmi.server.RMIClientSocketFactory;
  import java.rmi.server.RMIServerSocketFactory;
  import java.rmi.server.UnicastRemoteObject;
  import java.security.KeyException;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.jboss.security.srp.SRPServerInterface.SRPParameters;
  import org.jboss.security.srp.SRPVerifierStore.VerifierInfo;
  
  /** An implementation of the RMI SRPRemoteServerInterface interface.
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SRPRemoteServer extends UnicastRemoteObject implements 
SRPRemoteServerInterface
  {
      private Map sessionMap = Collections.synchronizedMap(new HashMap());
      private SRPVerifierStore verifierStore;
      private SRPServerListener listener;
  
      public interface SRPServerListener 
      {
          public void verifiedUser(String username, SRPServerSession session);
      }
  
      public SRPRemoteServer(SRPVerifierStore verifierStore) throws RemoteException
      {
          setVerifierStore(verifierStore);
      }
      public SRPRemoteServer(SRPVerifierStore verifierStore, int port) throws 
RemoteException
      {
          super(port);
          setVerifierStore(verifierStore);
      }
      public SRPRemoteServer(SRPVerifierStore verifierStore, int port, 
RMIClientSocketFactory csf,
          RMIServerSocketFactory ssf) throws RemoteException
      {
          super(port, csf, ssf);
          setVerifierStore(verifierStore);
      }
  
      /**
      */
      public void setVerifierStore(SRPVerifierStore verifierStore)
      {
          this.verifierStore = verifierStore;        
   System.out.println("setVerifierStore, "+verifierStore);
     }
  
      public void addSRPServerListener(SRPServerListener listener)
      {
          this.listener = listener;
      }
      public void removeSRPServerListener(SRPServerListener listener)
      {
          if( this.listener == listener )
              this.listener = null;
      }
  
      /** The start of a new client session.
      */
      public SRPParameters getSRPParameters(String username)
          throws KeyException, RemoteException
      {
  System.out.println("getSRPParameters, "+username);
          SRPParameters params = null;
          try
          {
              VerifierInfo info = verifierStore.getUserVerifier(username);
              if( info == null )
                  throw new KeyException("Unknown username: "+username);
              params = new SRPParameters();
              params.s = info.salt;
              params.g = info.g;
              params.N = info.N;
              // Create an SRP session
              SRPServerSession session = new SRPServerSession(username, params.s, 
info.verifier,
                  params.N, params.g);
              sessionMap.put(username, session);
          }
          catch(IOException e)
          {
              throw new RemoteException("Error during user info retrieval", e);
          }
          catch(KeyException e)
          {
              throw e;
          }
          catch(Throwable t)
          {
              t.printStackTrace();
          }
          return params;
      }
  
      public byte[] init(String username, byte[] A) throws SecurityException, 
RemoteException
      {
  System.out.println("init, "+username);
          SRPServerSession session = (SRPServerSession) sessionMap.get(username);
          if( session == null )
              throw new SecurityException("Failed to find active session for username: 
"+username);
  
          byte[] B = session.exponential();
          session.buildSessionKey(A);
  
          return B;
      }
  
      public byte[] verify(String username, byte[] M1) throws SecurityException, 
RemoteException
      {
  System.out.println("verify, "+username);
          SRPServerSession session = (SRPServerSession) sessionMap.get(username);
          if( session == null )
              throw new SecurityException("Failed to find active session for username: 
"+username);
  
          if( session.verify(M1) == false )
              throw new SecurityException("Failed to verify M1");
          if( listener != null )
              listener.verifiedUser(username, session);
          return session.getServerResponse();
      }
  
  }
  
  
  
  1.1                  
jbosssx/src/main/org/jboss/security/srp/SRPRemoteServerInterface.java
  
  Index: SRPRemoteServerInterface.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.Serializable;
  import java.rmi.Remote;
  
  /** An RMI version of the SRPServerInterface. This interface simply extends both
  the SRPServerInterface interface and the java.rmi.Remote to create an
  RMI legal interface.
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public interface SRPRemoteServerInterface extends Remote, SRPServerInterface
  {
      // All methods come from the SRPServerInterface
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPServerInterface.java
  
  Index: SRPServerInterface.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.Serializable;
  import java.rmi.RemoteException;
  import java.security.KeyException;
  
  /** An interface describing the message exchange of the SRP protocol as
  described in RFC2945. This is an RMI compatible interface, but it is not an
  RMI interface so that it can be used without RMI. For an RMI interface see
  SRPRemoteServerInterface
  
  @see SRPRemoteServerInterface
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public interface SRPServerInterface
  {
      /** The RFC2945 algorithm session parameters that the client and server
          agree to use.
      */
      public static class SRPParameters implements Cloneable, Serializable
      {
          /** The algorithm safe-prime modulus */
          public byte[] N;
          /** The algorithm primitive generator */
          public byte[] g;
          /** The random password salt originally used to verify the password */
          public byte[] s;
  
          public Object clone()
          {
              Object clone = null;
              try
              {
                  clone = super.clone();
              }
              catch(CloneNotSupportedException e)
              {
              }
              return clone;
          }
      }
  
      /** Get the SRP parameters to use for this session.
      */
      public SRPParameters getSRPParameters(String username) throws KeyException, 
RemoteException;
  
      /** Initiate the SRP algorithm. The client sends their username and 
      @param username, the user ID by which the client is known.
      @param A, the client public key = (g ^ a) % N
      @return byte[], ephemeral server public key B = (v + g ^ b) % N
      @throws KeyException, thrown if the username is not known by the server.
      @throws RemoteException, thrown by remote implementations
      */
      public byte[] init(String username, byte[] A) throws SecurityException, 
RemoteException;
  
      /** Initiate the SRP algorithm. The client sends their username and 
      @param username, the user ID by which the client is known. This is repeated to 
simplify
          the server session management.
      @param M1, the client hash of the session key; M1 = H(H(N) xor H(g) | H(U) | A | 
B | K)
      @return M2, the server hash of the client challenge; M2 = H(A | M1 | K)
      @throws SecurityException, thrown if M1 cannot be verified by the server
      @throws RemoteException, thrown by remote implementations
      */
      public byte[] verify(String username, byte[] M1) throws SecurityException, 
RemoteException;
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPServerSession.java
  
  Index: SRPServerSession.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.IOException;
  import java.math.BigInteger;
  import java.security.MessageDigest;
  import java.util.Arrays;
  
  import org.jboss.security.Util;
  
  /** The server side logic to the SRP protocol. The class was derived from
  the security.srp.SRPServer class. The class is intended to be used with a
  SRPClientSession 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.s, params.N, params.g);
  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 ([EMAIL PROTECTED]).
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SRPServerSession
  {
      private BigInteger N;
      private BigInteger g;
      private BigInteger v;
      private byte[] s;
      private BigInteger b;
      private BigInteger B;
      private byte[] key;
      /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */
      private MessageDigest clientHash;
      private byte[] M1;
      /** The M2 = H(A | M | K) hash */
      private MessageDigest serverHash;
      private byte[] M2;
  
      private static int B_LEN = 64;    // 64 bits for 'b'
  
      /** Creates a new SRP server session object from the username, password
          verifier, 
      @param username, the user ID
      @param vb, the password verifier byte sequence
      @param s, the password salt byte sequence
      @param nb, the algorithm safe-prime modulus byte sequence
      @param gb, the algorithm primitive generator byte sequence
      */
      public SRPServerSession(String username,byte[] s,byte[] vb,byte[] nb,byte[] gb)
      {
          this.s = s;
          this.v = new BigInteger(1, vb);
          this.g = new BigInteger(1, gb);
          this.N = new BigInteger(1, nb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("g: "+Util.tob64(gb));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("v: "+Util.tob64(vb));
          serverHash = Util.newDigest();
          clientHash = Util.newDigest();
          // H(N)
          byte[] hn = Util.newDigest().digest(nb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(N): "+Util.tob64(hn));
          // H(g)
          byte[] hg = Util.newDigest().digest(gb);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(g): "+Util.tob64(hg));
          // clientHash = H(N) xor H(g)
          byte[] hxg = Util.xor(hn, hg, 20);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("H(N) xor H(g): "+Util.tob64(hxg));
          clientHash.update(hxg);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g)]: "+Util.tob64(tmp.digest()));
          }
          // clientHash = H(N) xor H(g) | H(U)
          clientHash.update(Util.newDigest().digest(username.getBytes()));
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest()));
          }
          // clientHash = H(N) xor H(g) | H(U) | s
          clientHash.update(s);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s]: 
"+Util.tob64(tmp.digest()));
          }
          key = null;
      }
  
      /**
      * @returns The user's safe-prime modulus
      */
      public byte[] modulus() { return Util.trim(N.toByteArray()); }
  
      /**
      * @returns The user's primitive generator
      */
      public byte[] generator() { return Util.trim(g.toByteArray()); }
  
      /**
      * @returns The user's password salt
      */
      public byte[] salt() { return s; }
  
      /**
      * @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, Util.getPRNG());
              } while(b.compareTo(one) <= 0);
              B = v.add(g.modPow(b, N));
              if(B.compareTo(N) >= 0)
                  B = B.subtract(N);
          }
          return Util.trim(B.toByteArray());
      }
  
      /**
      * @param ab The client's exponential (parameter A).
      * @returns The secret shared session key between client and server
      */
      public void buildSessionKey(byte[] ab)
      {
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("A: "+Util.tob64(ab));
          byte[] nb = Util.trim(B.toByteArray());
          // clientHash = H(N) xor H(g) | H(U) | s | A
          clientHash.update(ab);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A]: 
"+Util.tob64(tmp.digest()));
          }
          // clientHash = H(N) xor H(g) | H(U) | A | B
          clientHash.update(nb);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A | B]: 
"+Util.tob64(tmp.digest()));
          }
          // serverHash = A
          serverHash.update(ab);
          // Calculate u as the first 32 bits of H(B)
          byte[] hB = Util.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( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("A: "+Util.tob64(A.toByteArray()));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("B: "+Util.tob64(B.toByteArray()));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("v: "+Util.tob64(v.toByteArray()));
          BigInteger u = new BigInteger(1, ub);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("u: "+Util.tob64(u.toByteArray()));
          BigInteger A_v2u = A.multiply(v.modPow(u, N)).mod(N);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("A * v^u: "+Util.tob64(A_v2u.toByteArray()));
          BigInteger S = A_v2u.modPow(b, N);
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("S: "+Util.tob64(S.toByteArray()));
          // K = SHA_Interleave(S)
          key = Util.sessionKeyHash(Util.trim(S.toByteArray()));
          if( PkgCategory.isTraceEnabled() )
              PkgCategory.trace("K: "+Util.tob64(key));
          // clientHash = H(N) xor H(g) | H(U) | A | B | K
          clientHash.update(key);
          if( PkgCategory.isTraceEnabled() )
          {
              MessageDigest tmp = Util.copy(clientHash);
              PkgCategory.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: 
"+Util.tob64(tmp.digest()));
          }
      }
  
      /**
      * @returns The secret shared session key between client and server
      */
      public byte[] sessionKey() { return key; }
  
      /**
      @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( PkgCategory.isTraceEnabled() )
          {
              PkgCategory.trace("verify M1: "+Util.tob64(M1));
              PkgCategory.trace("verify clientM1: "+Util.tob64(clientM1));
          }
          if( Arrays.equals(clientM1, M1) )
          {
              // serverHash = A | M
              serverHash.update(M1);
              // serverHash = A | M | K
              serverHash.update(key);
              if( PkgCategory.isTraceEnabled() )
              {
                  MessageDigest tmp = Util.copy(serverHash);
                  PkgCategory.trace("H(A | M | K)"+Util.tob64(tmp.digest()));
              }
              valid = true;
          }
          return valid;
      }
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SRPVerifierStore.java
  
  Index: SRPVerifierStore.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.security.srp;
  
  import java.io.IOException;
  import java.io.Serializable;
  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 [EMAIL PROTECTED]
  */
  public interface SRPVerifierStore
  {
      public static class VerifierInfo implements Serializable
      {
          public String username;
          public byte[] verifier;
          public byte[] salt;
          public byte[] g;
          public byte[] N;
      }
  
      public VerifierInfo getUserVerifier(String username) throws KeyException, 
IOException;
      public void setUserVerifier(String username, VerifierInfo info) throws 
IOException;
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/SerialObjectStore.java
  
  Index: SerialObjectStore.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.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.io.Serializable;
  import java.math.BigInteger;
  import java.security.KeyException;
  import java.security.MessageDigest;
  import java.security.NoSuchAlgorithmException;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.jboss.security.Util;
  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.
  
  @see #addUser(String, String)
  @see #delUser(String)
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class SerialObjectStore implements SRPVerifierStore
  {
      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
          {
              Util.init();
          }
          catch(NoSuchAlgorithmException e)
          {
              e.printStackTrace();
              throw new IOException("Failed to initialzed security utils: 
"+e.getMessage());
          }
          N = SRPConf.getDefaultParams().N();
          g = SRPConf.getDefaultParams().g();
      }
  
  // --- 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);
      }
  // --- 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)
      {
          VerifierInfo info = new VerifierInfo();
          info.username = username;
          long r = Util.nextLong();
          String rs = Long.toHexString(r);
          info.salt = rs.getBytes();
          info.verifier = Util.calculateVerifier(username, password,
              info.salt, N, g);
          info.g = g.toByteArray();
          info.N = N.toByteArray();
          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);
      }
  }
  
  
  
  1.1                  jbosssx/src/main/org/jboss/security/srp/TracePriority.java
  
  Index: TracePriority.java
  ===================================================================
  package org.jboss.security.srp;
  
  import org.apache.log4j.Priority;
  
  /** Adds a trace priority that is below the standard log4j debug priority.
  
  @see org.apache.log4j.Category
  
  @author [EMAIL PROTECTED]
  @version $Revision: 1.1 $
  */
  public class TracePriority extends Priority
  {
      static final int TRACE_INT = 800;
      public static final TracePriority TRACE = new TracePriority(TRACE_INT, "TRACE");
  
      protected TracePriority(int level, String strLevel)
      {
          super(level, strLevel, 7);
      }
  
      public static Priority toPriority(String name)
      {
          if( name == null )
             return TRACE;
  
          Priority p = TRACE;
          if( name.charAt(0) != 'T' )
              p = Priority.toPriority(name);
          return p;
      }
  
      public static Priority toPriority(int i) throws IllegalArgumentException
      {
          Priority p;
          if( i == TRACE_INT )
              p = TRACE;
          else
              p = Priority.toPriority(i);
          return p;
      }
  }
  
  
  

Reply via email to