KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > security > srp > SRPServerSession


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.security.srp;
23
24 import java.io.Serializable JavaDoc;
25 import java.math.BigInteger JavaDoc;
26 import java.security.MessageDigest JavaDoc;
27 import java.security.NoSuchAlgorithmException JavaDoc;
28 import java.util.Arrays JavaDoc;
29
30 import org.jboss.logging.Logger;
31 import org.jboss.security.Util;
32
33 /** The server side logic to the SRP protocol. The class is the server side
34  equivalent of the SRPClientSession object. An implementation of
35  SRPServerInterface creates an SRPServerSession on the start of a login
36  session.
37  
38  The client side algorithm using these classes consists of:
39  
40  1. Get server, SRPServerInterface server = (SRPServerInterface) Naming.lookup(...);
41  2. Get SRP parameters, SRPParameters params = server.getSRPParameters(username);
42  3. Create a client session, SRPClientSession client = new SRPClientSession(username, password, params);
43  4. Exchange public keys, byte[] A = client.exponential();
44  byte[] B = server.init(username, A);
45  5. Exchange challenges, byte[] M1 = client.response(B);
46  byte[] M2 = server.verify(username, M1);
47  6. Verify the server response, if( client.verify(M2) == false )
48  throw new SecurityException("Failed to validate server reply");
49  7. Validation complete
50  
51  Note that these steps are stateful. They must be performed in order and a
52  step cannot be repeated to update the session state.
53  
54  This product uses the 'Secure Remote Password' cryptographic
55  authentication system developed by Tom Wu (tjw@CS.Stanford.EDU).
56  
57  @author Scott.Stark@jboss.org
58  @version $Revision: 40096 $
59  */

60 public class SRPServerSession implements Serializable JavaDoc
61 {
62    /** The serial version ID
63     @since 1.6
64     */

65    static final long serialVersionUID = -2448005747721323704L;
66    private static int B_LEN = 64; // 64 bits for 'b'
67
private static Logger log = Logger.getLogger(SRPServerSession.class);
68
69    private SRPParameters params;
70    private BigInteger JavaDoc N;
71    private BigInteger JavaDoc g;
72    private BigInteger JavaDoc v;
73    private BigInteger JavaDoc b;
74    private BigInteger JavaDoc B;
75    private byte[] K;
76    /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */
77    private transient MessageDigest JavaDoc clientHash;
78    private byte[] M1;
79    /** The M2 = H(A | M | K) hash */
80    private transient MessageDigest JavaDoc serverHash;
81    private byte[] M2;
82    
83    /** Creates a new SRP server session object from the username, password
84     verifier, and session parameters.
85     @param username, the user ID
86     @param vb, the password verifier byte sequence
87     @param params, the SRP parameters for the session
88     */

89    public SRPServerSession(String JavaDoc username, byte[] vb, SRPParameters params)
90    {
91       this.params = params;
92       this.v = new BigInteger JavaDoc(1, vb);
93       this.g = new BigInteger JavaDoc(1, params.g);
94       this.N = new BigInteger JavaDoc(1, params.N);
95       if( log.isTraceEnabled() )
96          log.trace("g: "+Util.tob64(params.g));
97       if( log.isTraceEnabled() )
98          log.trace("v: "+Util.tob64(vb));
99       serverHash = Util.newDigest();
100       clientHash = Util.newDigest();
101       // H(N)
102
byte[] hn = Util.newDigest().digest(params.N);
103       if( log.isTraceEnabled() )
104          log.trace("H(N): "+Util.tob64(hn));
105       // H(g)
106
byte[] hg = Util.newDigest().digest(params.g);
107       if( log.isTraceEnabled() )
108          log.trace("H(g): "+Util.tob64(hg));
109       // clientHash = H(N) xor H(g)
110
byte[] hxg = Util.xor(hn, hg, 20);
111       if( log.isTraceEnabled() )
112          log.trace("H(N) xor H(g): "+Util.tob64(hxg));
113       clientHash.update(hxg);
114       if( log.isTraceEnabled() )
115       {
116          MessageDigest JavaDoc tmp = Util.copy(clientHash);
117          log.trace("H[H(N) xor H(g)]: "+Util.tob64(tmp.digest()));
118       }
119       // clientHash = H(N) xor H(g) | H(U)
120
clientHash.update(Util.newDigest().digest(username.getBytes()));
121       if( log.isTraceEnabled() )
122       {
123          MessageDigest JavaDoc tmp = Util.copy(clientHash);
124          log.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest()));
125       }
126       // clientHash = H(N) xor H(g) | H(U) | s
127
clientHash.update(params.s);
128       if( log.isTraceEnabled() )
129       {
130          MessageDigest JavaDoc tmp = Util.copy(clientHash);
131          log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.tob64(tmp.digest()));
132       }
133       K = null;
134    }
135    
136    /**
137     * @returns The user's password salt
138     */

139    public SRPParameters getParameters()
140    {
141       return params;
142    }
143    
144    /**
145     * @returns The exponential residue (parameter B) to be sent to the
146     * client.
147     */

148    public byte[] exponential()
149    {
150       if(B == null)
151       {
152          BigInteger JavaDoc one = BigInteger.valueOf(1);
153          do
154          {
155             b = new BigInteger JavaDoc(B_LEN, Util.getPRNG());
156          } while(b.compareTo(one) <= 0);
157          B = v.add(g.modPow(b, N));
158          if(B.compareTo(N) >= 0)
159             B = B.subtract(N);
160       }
161       return Util.trim(B.toByteArray());
162    }
163    
164    /**
165    @param ab The client's exponential (parameter A).
166    @returns The secret shared session K between client and server
167     @exception NoSuchAlgorithmException thrown if the session key
168     MessageDigest algorithm cannot be found.
169     */

170    public void buildSessionKey(byte[] ab) throws NoSuchAlgorithmException JavaDoc
171    {
172       if( log.isTraceEnabled() )
173          log.trace("A: "+Util.tob64(ab));
174       byte[] nb = Util.trim(B.toByteArray());
175       // clientHash = H(N) xor H(g) | H(U) | s | A
176
clientHash.update(ab);
177       if( log.isTraceEnabled() )
178       {
179          MessageDigest JavaDoc tmp = Util.copy(clientHash);
180          log.trace("H[H(N) xor H(g) | H(U) | s | A]: "+Util.tob64(tmp.digest()));
181       }
182       // clientHash = H(N) xor H(g) | H(U) | A | B
183
clientHash.update(nb);
184       if( log.isTraceEnabled() )
185       {
186          MessageDigest JavaDoc tmp = Util.copy(clientHash);
187          log.trace("H[H(N) xor H(g) | H(U) | s | A | B]: "+Util.tob64(tmp.digest()));
188       }
189       // serverHash = A
190
serverHash.update(ab);
191       // Calculate u as the first 32 bits of H(B)
192
byte[] hB = Util.newDigest().digest(nb);
193       byte[] ub =
194       {hB[0], hB[1], hB[2], hB[3]};
195       // Calculate S = (A * v^u) ^ b % N
196
BigInteger JavaDoc A = new BigInteger JavaDoc(1, ab);
197       if( log.isTraceEnabled() )
198          log.trace("A: "+Util.tob64(A.toByteArray()));
199       if( log.isTraceEnabled() )
200          log.trace("B: "+Util.tob64(B.toByteArray()));
201       if( log.isTraceEnabled() )
202          log.trace("v: "+Util.tob64(v.toByteArray()));
203       BigInteger JavaDoc u = new BigInteger JavaDoc(1, ub);
204       if( log.isTraceEnabled() )
205          log.trace("u: "+Util.tob64(u.toByteArray()));
206       BigInteger JavaDoc A_v2u = A.multiply(v.modPow(u, N)).mod(N);
207       if( log.isTraceEnabled() )
208          log.trace("A * v^u: "+Util.tob64(A_v2u.toByteArray()));
209       BigInteger JavaDoc S = A_v2u.modPow(b, N);
210       if( log.isTraceEnabled() )
211          log.trace("S: "+Util.tob64(S.toByteArray()));
212       // K = SessionHash(S)
213
MessageDigest JavaDoc sessionDigest = MessageDigest.getInstance(params.hashAlgorithm);
214       K = sessionDigest.digest(S.toByteArray());
215       if( log.isTraceEnabled() )
216          log.trace("K: "+Util.tob64(K));
217       // clientHash = H(N) xor H(g) | H(U) | A | B | K
218
clientHash.update(K);
219       if( log.isTraceEnabled() )
220       {
221          MessageDigest JavaDoc tmp = Util.copy(clientHash);
222          log.trace("H[H(N) xor H(g) | H(U) | s | A | B | K]: "+Util.tob64(tmp.digest()));
223       }
224    }
225    
226    /** Returns the negotiated session K, K = SessionHash(S)
227     @return the private session K byte[]
228     @throws SecurityException - if the current thread does not have an
229     getSessionKey SRPPermission.
230     */

231    public byte[] getSessionKey() throws SecurityException JavaDoc
232    {
233       SecurityManager JavaDoc sm = System.getSecurityManager();
234       if( sm != null )
235       {
236          SRPPermission p = new SRPPermission("getSessionKey");
237          sm.checkPermission(p);
238       }
239       return K;
240    }
241
242    /**
243     @returns M2 = H(A | M | K)
244     */

245    public byte[] getServerResponse()
246    {
247       if( M2 == null )
248          M2 = serverHash.digest();
249       return M2;
250    }
251    public byte[] getClientResponse()
252    {
253       return M1;
254    }
255    
256    /**
257     * @param resp The client's response to the server's challenge
258     * @returns True if and only if the client's response was correct.
259     */

260    public boolean verify(byte[] clientM1)
261    {
262       boolean valid = false;
263       // M1 = H(H(N) xor H(g) | H(U) | A | B | K)
264
M1 = clientHash.digest();
265       if( log.isTraceEnabled() )
266       {
267          log.trace("verify M1: "+Util.tob64(M1));
268          log.trace("verify clientM1: "+Util.tob64(clientM1));
269       }
270       if( Arrays.equals(clientM1, M1) )
271       {
272          // serverHash = A | M
273
serverHash.update(M1);
274          // serverHash = A | M | K
275
serverHash.update(K);
276          if( log.isTraceEnabled() )
277          {
278             MessageDigest JavaDoc tmp = Util.copy(serverHash);
279             log.trace("H(A | M1 | K)"+Util.tob64(tmp.digest()));
280          }
281          valid = true;
282       }
283       return valid;
284    }
285 }
286
Popular Tags