User: starksm Date: 02/03/07 21:32:16 Modified: src/main/org/jboss/security/srp SRPClientSession.java SRPConf.java SRPRemoteServer.java SRPServerInterface.java SRPServerSession.java SRPService.java SerialObjectStore.java Log: Update the SRP sessions to support arbitrary message digests of the session key and a cipher algorithm Revision Changes Path 1.5 +216 -207 jbosssx/src/main/org/jboss/security/srp/SRPClientSession.java Index: SRPClientSession.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPClientSession.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SRPClientSession.java 8 Feb 2002 23:53:33 -0000 1.4 +++ SRPClientSession.java 8 Mar 2002 05:32:16 -0000 1.5 @@ -17,224 +17,233 @@ import org.jboss.security.Util; /** 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.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.4 $ -*/ + 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 ([EMAIL PROTECTED]). + + @author [EMAIL PROTECTED] + @version $Revision: 1.5 $ + */ public class SRPClientSession { - private static Logger log = Logger.getLogger(SRPClientSession.class); - 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, + 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 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 + @param password, the user clear text password + @param params, the SRP parameters for the session */ - 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( log.isTraceEnabled() ) - log.trace("g: "+Util.tob64(gb)); - // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = Util.calculatePasswordHash(username, password, s); - if( log.isTraceEnabled() ) - log.trace("x: "+Util.tob64(xb)); - this.x = new BigInteger(1, xb); - this.v = g.modPow(x, N); // g^x % N - if( log.isTraceEnabled() ) - log.trace("v: "+Util.tob64(v.toByteArray())); - - serverHash = Util.newDigest(); - clientHash = Util.newDigest(); - // H(N) - byte[] hn = Util.newDigest().digest(nb); - if( log.isTraceEnabled() ) - log.trace("H(N): "+Util.tob64(hn)); - // H(g) - byte[] hg = Util.newDigest().digest(gb); - if( log.isTraceEnabled() ) - log.trace("H(g): "+Util.tob64(hg)); - // clientHash = H(N) xor H(g) - byte[] hxg = Util.xor(hn, hg, 20); - if( log.isTraceEnabled() ) - log.trace("H(N) xor H(g): "+Util.tob64(hxg)); - clientHash.update(hxg); - if( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.tob64(tmp.digest())); - } - key = null; - } - - /** + public SRPClientSession(String username, char[] password, SRPParameters params) + { + try + { + // Initialize the secure random number and message digests + Util.init(); + } + catch(NoSuchAlgorithmException e) + { + } + this.params = params; + this.g = new BigInteger(1, params.g); + this.N = new BigInteger(1, params.N); + if( log.isTraceEnabled() ) + log.trace("g: "+Util.tob64(params.g)); + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = Util.calculatePasswordHash(username, password, params.s); + if( log.isTraceEnabled() ) + log.trace("x: "+Util.tob64(xb)); + this.x = new BigInteger(1, xb); + this.v = g.modPow(x, N); // g^x % N + if( log.isTraceEnabled() ) + log.trace("v: "+Util.tob64(v.toByteArray())); + + serverHash = Util.newDigest(); + clientHash = Util.newDigest(); + // H(N) + byte[] hn = Util.newDigest().digest(params.N); + if( log.isTraceEnabled() ) + log.trace("H(N): "+Util.tob64(hn)); + // H(g) + byte[] hg = Util.newDigest().digest(params.g); + if( log.isTraceEnabled() ) + log.trace("H(g): "+Util.tob64(hg)); + // clientHash = H(N) xor H(g) + byte[] hxg = Util.xor(hn, hg, 20); + if( log.isTraceEnabled() ) + log.trace("H(N) xor H(g): "+Util.tob64(hxg)); + clientHash.update(hxg); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.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( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest())); + } + // clientHash = H(N) xor H(g) | H(U) | s + clientHash.update(params.s); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.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) - { - 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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.trace("H[H(N) xor H(g) | H(U) | s | A]: "+Util.tob64(tmp.digest())); - } - // serverHash = A - serverHash.update(Abytes); - } - return Abytes; - } - - /** + 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( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.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) + @exception NoSuchAlgorithmException thrown if the session key + MessageDigest algorithm cannot be found. */ - public byte[] response(byte[] Bbytes) - { - // clientHash = H(N) xor H(g) | H(U) | s | A | B - clientHash.update(Bbytes); - if( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - log.trace("B: "+Util.tob64(B.toByteArray())); - if( B.compareTo(v) < 0 ) - B = B.add(N); - if( log.isTraceEnabled() ) - log.trace("B': "+Util.tob64(B.toByteArray())); - if( log.isTraceEnabled() ) - log.trace("v: "+Util.tob64(v.toByteArray())); - BigInteger u = new BigInteger(1, ub); - if( log.isTraceEnabled() ) - log.trace("u: "+Util.tob64(u.toByteArray())); - BigInteger B_v = B.subtract(v); - if( log.isTraceEnabled() ) - log.trace("B - v: "+Util.tob64(B_v.toByteArray())); - BigInteger a_ux = a.add(u.multiply(x)); - if( log.isTraceEnabled() ) - log.trace("a + u * x: "+Util.tob64(a_ux.toByteArray())); - BigInteger S = B_v.modPow(a_ux, N); - if( log.isTraceEnabled() ) - log.trace("S: "+Util.tob64(S.toByteArray())); - // K = SHA_Interleave(S) - key = Util.sessionKeyHash(Util.trim(S.toByteArray())); - if( log.isTraceEnabled() ) - log.trace("K: "+Util.tob64(key)); - // clientHash = H(N) xor H(g) | H(U) | A | B | K - clientHash.update(key); - byte[] M1 = clientHash.digest(); - if( log.isTraceEnabled() ) - log.trace("M1: H[H(N) xor H(g) | H(U) | s | A | B | K]: "+Util.tob64(M1)); - serverHash.update(M1); - serverHash.update(key); - if( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(serverHash); - log.trace("H[A | M1 | K]: "+Util.tob64(tmp.digest())); - } - return M1; - } - /** + 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 = Util.copy(clientHash); + log.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( log.isTraceEnabled() ) + log.trace("B: "+Util.tob64(B.toByteArray())); + if( B.compareTo(v) < 0 ) + B = B.add(N); + if( log.isTraceEnabled() ) + log.trace("B': "+Util.tob64(B.toByteArray())); + if( log.isTraceEnabled() ) + log.trace("v: "+Util.tob64(v.toByteArray())); + BigInteger u = new BigInteger(1, ub); + if( log.isTraceEnabled() ) + log.trace("u: "+Util.tob64(u.toByteArray())); + BigInteger B_v = B.subtract(v); + if( log.isTraceEnabled() ) + log.trace("B - v: "+Util.tob64(B_v.toByteArray())); + BigInteger a_ux = a.add(u.multiply(x)); + if( log.isTraceEnabled() ) + log.trace("a + u * x: "+Util.tob64(a_ux.toByteArray())); + BigInteger S = B_v.modPow(a_ux, N); + if( log.isTraceEnabled() ) + log.trace("S: "+Util.tob64(S.toByteArray())); + // K = SessionHash(S) + MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); + K = sessionDigest.digest(S.toByteArray()); + if( log.isTraceEnabled() ) + log.trace("K: "+Util.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]: "+Util.tob64(M1)); + serverHash.update(M1); + serverHash.update(K); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(serverHash); + log.trace("H[A | M1 | 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( log.isTraceEnabled() ) - { - log.trace("verify serverM2: "+Util.tob64(M2)); - log.trace("verify M2: "+Util.tob64(myM2)); - } - return valid; - } - - /** Returns the negotiated session key, K = SHA_Interleave(S) - @return the private session key byte[] + 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: "+Util.tob64(M2)); + log.trace("verify M2: "+Util.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. + getSessionKey SRPPermission. */ - public byte[] getSessionKey() throws SecurityException - { - SRPPermission p = new SRPPermission("getSessionKey"); - AccessController.checkPermission(p); - return key; - } + public byte[] getSessionKey() throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if( sm != null ) + { + SRPPermission p = new SRPPermission("getSessionKey"); + sm.checkPermission(p); + } + return K; + } } 1.4 +2 -2 jbosssx/src/main/org/jboss/security/srp/SRPConf.java Index: SRPConf.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPConf.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SRPConf.java 8 Feb 2002 23:53:33 -0000 1.3 +++ SRPConf.java 8 Mar 2002 05:32:16 -0000 1.4 @@ -1,5 +1,5 @@ /* - * JBoss, the OpenSource EJB server + * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. @@ -18,7 +18,7 @@ Jhong for the SRP Distribution (http://srp.stanford.edu/srp/). @author [EMAIL PROTECTED] -@version $Revision: 1.3 $ +@version $Revision: 1.4 $ */ public class SRPConf { 1.4 +8 -9 jbosssx/src/main/org/jboss/security/srp/SRPRemoteServer.java Index: SRPRemoteServer.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPRemoteServer.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SRPRemoteServer.java 8 Feb 2002 23:53:33 -0000 1.3 +++ SRPRemoteServer.java 8 Mar 2002 05:32:16 -0000 1.4 @@ -12,19 +12,20 @@ import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; 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.security.Util; -import org.jboss.security.srp.SRPServerInterface.SRPParameters; +import org.jboss.security.srp.SRPParameters; import org.jboss.security.srp.SRPVerifierStore.VerifierInfo; /** An implementation of the RMI SRPRemoteServerInterface interface. @author [EMAIL PROTECTED] -@version $Revision: 1.3 $ +@version $Revision: 1.4 $ */ public class SRPRemoteServer extends UnicastRemoteObject implements SRPRemoteServerInterface { @@ -96,10 +97,7 @@ 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; + params = new SRPParameters(info.N, info.g, info.salt); if( log.isTraceEnabled() ) { log.trace("N: "+Util.tob64(params.N)); @@ -111,8 +109,8 @@ log.trace("H(g): "+Util.tob64(hg)); } // Create an SRP session - SRPServerSession session = new SRPServerSession(username, params.s, info.verifier, - params.N, params.g); + SRPServerSession session = new SRPServerSession(username, info.verifier, + params); sessionMap.put(username, session); } catch(IOException e) @@ -130,7 +128,8 @@ return params; } - public byte[] init(String username, byte[] A) throws SecurityException, RemoteException + public byte[] init(String username, byte[] A) throws SecurityException, + NoSuchAlgorithmException, RemoteException { log.trace("init, "+username); SRPServerSession session = (SRPServerSession) sessionMap.get(username); 1.4 +5 -29 jbosssx/src/main/org/jboss/security/srp/SRPServerInterface.java Index: SRPServerInterface.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPServerInterface.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SRPServerInterface.java 8 Feb 2002 23:53:33 -0000 1.3 +++ SRPServerInterface.java 8 Mar 2002 05:32:16 -0000 1.4 @@ -1,5 +1,5 @@ /* - * JBoss, the OpenSource EJB server + * JBoss, the OpenSource J2EE WebOS * * Distributable under LGPL license. * See terms of license at gnu.org. @@ -9,6 +9,7 @@ import java.io.Serializable; import java.rmi.RemoteException; import java.security.KeyException; +import java.security.NoSuchAlgorithmException; /** An interface describing the message exchange of the SRP protocol as described in RFC2945. This is an RMI compatible interface in that all methods @@ -19,36 +20,10 @@ @see org.jboss.security.srp.SRPRemoteServerInterface @author [EMAIL PROTECTED] -@version $Revision: 1.3 $ +@version $Revision: 1.4 $ */ 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; @@ -60,7 +35,8 @@ @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; + public byte[] init(String username, byte[] A) throws SecurityException, + NoSuchAlgorithmException, 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 1.5 +229 -229 jbosssx/src/main/org/jboss/security/srp/SRPServerSession.java Index: SRPServerSession.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPServerSession.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- SRPServerSession.java 8 Feb 2002 23:53:33 -0000 1.4 +++ SRPServerSession.java 8 Mar 2002 05:32:16 -0000 1.5 @@ -10,258 +10,258 @@ import java.math.BigInteger; import java.security.AccessController; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.jboss.logging.Logger; import org.jboss.security.Util; /** 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.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.4 $ -*/ + 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 ([EMAIL PROTECTED]). + + @author [EMAIL PROTECTED] + @version $Revision: 1.5 $ + */ public class SRPServerSession { - private static int B_LEN = 64; // 64 bits for 'b' - private static Logger log = Logger.getLogger(SRPServerSession.class); - - 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' + private static Logger log = Logger.getLogger(SRPServerSession.class); - /** Creates a new SRP server session object from the username, password - verifier, + 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 MessageDigest clientHash; + private byte[] M1; + /** The M2 = H(A | M | K) hash */ + private 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 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( log.isTraceEnabled() ) - log.trace("g: "+Util.tob64(gb)); - if( log.isTraceEnabled() ) - log.trace("v: "+Util.tob64(vb)); - serverHash = Util.newDigest(); - clientHash = Util.newDigest(); - // H(N) - byte[] hn = Util.newDigest().digest(nb); - if( log.isTraceEnabled() ) - log.trace("H(N): "+Util.tob64(hn)); - // H(g) - byte[] hg = Util.newDigest().digest(gb); - if( log.isTraceEnabled() ) - log.trace("H(g): "+Util.tob64(hg)); - // clientHash = H(N) xor H(g) - byte[] hxg = Util.xor(hn, hg, 20); - if( log.isTraceEnabled() ) - log.trace("H(N) xor H(g): "+Util.tob64(hxg)); - clientHash.update(hxg); - if( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.tob64(tmp.digest())); - } - key = null; - } - - /** - * @returns The user's safe-prime modulus + @param params, the SRP parameters for the session */ - public byte[] modulus() { return Util.trim(N.toByteArray()); } - - /** - * @returns The user's primitive generator - */ - public byte[] generator() { return Util.trim(g.toByteArray()); } - - /** + 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: "+Util.tob64(params.g)); + if( log.isTraceEnabled() ) + log.trace("v: "+Util.tob64(vb)); + serverHash = Util.newDigest(); + clientHash = Util.newDigest(); + // H(N) + byte[] hn = Util.newDigest().digest(params.N); + if( log.isTraceEnabled() ) + log.trace("H(N): "+Util.tob64(hn)); + // H(g) + byte[] hg = Util.newDigest().digest(params.g); + if( log.isTraceEnabled() ) + log.trace("H(g): "+Util.tob64(hg)); + // clientHash = H(N) xor H(g) + byte[] hxg = Util.xor(hn, hg, 20); + if( log.isTraceEnabled() ) + log.trace("H(N) xor H(g): "+Util.tob64(hxg)); + clientHash.update(hxg); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.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( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest())); + } + // clientHash = H(N) xor H(g) | H(U) | s + clientHash.update(params.s); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.tob64(tmp.digest())); + } + K = null; + } + + /** * @returns The user's password salt */ - public byte[] salt() { return s; } - - /** + 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, 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( log.isTraceEnabled() ) - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.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( log.isTraceEnabled() ) - log.trace("A: "+Util.tob64(A.toByteArray())); - if( log.isTraceEnabled() ) - log.trace("B: "+Util.tob64(B.toByteArray())); - if( log.isTraceEnabled() ) - log.trace("v: "+Util.tob64(v.toByteArray())); - BigInteger u = new BigInteger(1, ub); - if( log.isTraceEnabled() ) - log.trace("u: "+Util.tob64(u.toByteArray())); - BigInteger A_v2u = A.multiply(v.modPow(u, N)).mod(N); - if( log.isTraceEnabled() ) - log.trace("A * v^u: "+Util.tob64(A_v2u.toByteArray())); - BigInteger S = A_v2u.modPow(b, N); - if( log.isTraceEnabled() ) - log.trace("S: "+Util.tob64(S.toByteArray())); - // K = SHA_Interleave(S) - key = Util.sessionKeyHash(Util.trim(S.toByteArray())); - if( log.isTraceEnabled() ) - log.trace("K: "+Util.tob64(key)); - // clientHash = H(N) xor H(g) | H(U) | A | B | K - clientHash.update(key); - if( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(clientHash); - log.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: "+Util.tob64(tmp.digest())); - } - } - - /** Returns the negotiated session key, K = SHA_Interleave(S) - @return the private session key byte[] + 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 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: "+Util.tob64(ab)); + byte[] nb = Util.trim(B.toByteArray()); + // clientHash = H(N) xor H(g) | H(U) | s | A + clientHash.update(ab); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.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( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.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( log.isTraceEnabled() ) + log.trace("A: "+Util.tob64(A.toByteArray())); + if( log.isTraceEnabled() ) + log.trace("B: "+Util.tob64(B.toByteArray())); + if( log.isTraceEnabled() ) + log.trace("v: "+Util.tob64(v.toByteArray())); + BigInteger u = new BigInteger(1, ub); + if( log.isTraceEnabled() ) + log.trace("u: "+Util.tob64(u.toByteArray())); + BigInteger A_v2u = A.multiply(v.modPow(u, N)).mod(N); + if( log.isTraceEnabled() ) + log.trace("A * v^u: "+Util.tob64(A_v2u.toByteArray())); + BigInteger S = A_v2u.modPow(b, N); + if( log.isTraceEnabled() ) + log.trace("S: "+Util.tob64(S.toByteArray())); + // K = SessionHash(S) + MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); + K = sessionDigest.digest(S.toByteArray()); + if( log.isTraceEnabled() ) + log.trace("K: "+Util.tob64(K)); + // clientHash = H(N) xor H(g) | H(U) | A | B | K + clientHash.update(K); + if( log.isTraceEnabled() ) + { + MessageDigest tmp = Util.copy(clientHash); + log.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: "+Util.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. + getSessionKey SRPPermission. */ - public byte[] getSessionKey() throws SecurityException - { - SRPPermission p = new SRPPermission("getSessionKey"); - AccessController.checkPermission(p); - return key; - } + 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; - } - - /** + 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: "+Util.tob64(M1)); - log.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( log.isTraceEnabled() ) - { - MessageDigest tmp = Util.copy(serverHash); - log.trace("H(A | M1 | K)"+Util.tob64(tmp.digest())); - } - valid = true; - } - return valid; - } + 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: "+Util.tob64(M1)); + log.trace("verify clientM1: "+Util.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 = Util.copy(serverHash); + log.trace("H(A | M1 | K)"+Util.tob64(tmp.digest())); + } + valid = true; + } + return valid; + } } 1.7 +4 -3 jbosssx/src/main/org/jboss/security/srp/SRPService.java Index: SRPService.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SRPService.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- SRPService.java 8 Feb 2002 23:53:33 -0000 1.6 +++ SRPService.java 8 Mar 2002 05:32:16 -0000 1.7 @@ -29,9 +29,10 @@ system described in RFC2945. @author [EMAIL PROTECTED] - @version $Revision: 1.6 $ + @version $Revision: 1.7 $ */ -public class SRPService extends ServiceMBeanSupport implements SRPServiceMBean, SRPServerListener +public class SRPService extends ServiceMBeanSupport + implements SRPServiceMBean, SRPServerListener { /** * @supplierRole RMI Access @@ -41,7 +42,7 @@ */ private SRPRemoteServer server; private int serverPort = 10099; - + /** * @supplierRole password store * @supplierCardinality 1 1.4 +4 -3 jbosssx/src/main/org/jboss/security/srp/SerialObjectStore.java Index: SerialObjectStore.java =================================================================== RCS file: /cvsroot/jboss/jbosssx/src/main/org/jboss/security/srp/SerialObjectStore.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SerialObjectStore.java 8 Feb 2002 23:53:33 -0000 1.3 +++ SerialObjectStore.java 8 Mar 2002 05:32:16 -0000 1.4 @@ -40,7 +40,7 @@ @see #delUser(String) @author [EMAIL PROTECTED] -@version $Revision: 1.3 $ +@version $Revision: 1.4 $ */ public class SerialObjectStore implements SRPVerifierStore { @@ -145,7 +145,8 @@ info.salt = rs.getBytes(); try { - info.verifier = Util.calculateVerifier(username, password, + char[] pass = password.toCharArray(); + info.verifier = Util.calculateVerifier(username, pass, info.salt, N, g); info.g = g.toByteArray(); info.N = N.toByteArray(); @@ -154,7 +155,7 @@ log.trace("N: "+Util.tob64(info.N)); log.trace("g: "+Util.tob64(info.g)); log.trace("s: "+Util.tob64(info.salt)); - byte[] xb = Util.calculatePasswordHash(username, password, info.salt); + byte[] xb = Util.calculatePasswordHash(username, pass, info.salt); log.trace("x: "+Util.tob64(xb)); log.trace("v: "+Util.tob64(info.verifier)); byte[] hn = Util.newDigest().digest(info.N);
_______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development