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;
}
}