KickJava   Java API By Example, From Geeks To Geeks.

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


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

57 public class SRPClientSession
58 {
59    private static Logger log = Logger.getLogger(SRPClientSession.class);
60    private SRPParameters params;
61    private BigInteger JavaDoc N;
62    private BigInteger JavaDoc g;
63    private BigInteger JavaDoc x;
64    private BigInteger JavaDoc v;
65    private byte[] s;
66    private BigInteger JavaDoc a;
67    private BigInteger JavaDoc A;
68    private byte[] K;
69    /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */
70    private MessageDigest JavaDoc clientHash;
71    /** The M2 = H(A | M | K) hash */
72    private MessageDigest JavaDoc serverHash;
73    
74    private static int A_LEN = 64;
75    
76    /** Creates a new SRP server session object from the username, password
77     verifier,
78     @param username, the user ID
79     @param password, the user clear text password
80     @param params, the SRP parameters for the session
81     */

82    public SRPClientSession(String JavaDoc username, char[] password, SRPParameters params)
83    {
84       this(username, password, params, null);
85    }
86
87    /** Creates a new SRP server session object from the username, password
88     verifier,
89     @param username, the user ID
90     @param password, the user clear text password
91     @param params, the SRP parameters for the session
92     @param abytes, the random exponent used in the A public key. This must be
93       8 bytes in length.
94     */

95    public SRPClientSession(String JavaDoc username, char[] password, SRPParameters params,
96       byte[] abytes)
97    {
98       try
99       {
100          // Initialize the secure random number and message digests
101
Util.init();
102       }
103       catch(NoSuchAlgorithmException JavaDoc e)
104       {
105       }
106       this.params = params;
107       this.g = new BigInteger JavaDoc(1, params.g);
108       this.N = new BigInteger JavaDoc(1, params.N);
109       if( abytes != null )
110       {
111          if( 8*abytes.length != A_LEN )
112             throw new IllegalArgumentException JavaDoc("The abytes param must be "
113                +(A_LEN/8)+" in length, abytes.length="+abytes.length);
114          this.a = new BigInteger JavaDoc(abytes);
115       }
116
117       if( log.isTraceEnabled() )
118          log.trace("g: "+Util.tob64(params.g));
119       // Calculate x = H(s | H(U | ':' | password))
120
byte[] xb = Util.calculatePasswordHash(username, password, params.s);
121       if( log.isTraceEnabled() )
122          log.trace("x: "+Util.tob64(xb));
123       this.x = new BigInteger JavaDoc(1, xb);
124       this.v = g.modPow(x, N); // g^x % N
125
if( log.isTraceEnabled() )
126          log.trace("v: "+Util.tob64(v.toByteArray()));
127       
128       serverHash = Util.newDigest();
129       clientHash = Util.newDigest();
130       // H(N)
131
byte[] hn = Util.newDigest().digest(params.N);
132       if( log.isTraceEnabled() )
133          log.trace("H(N): "+Util.tob64(hn));
134       // H(g)
135
byte[] hg = Util.newDigest().digest(params.g);
136       if( log.isTraceEnabled() )
137          log.trace("H(g): "+Util.tob64(hg));
138       // clientHash = H(N) xor H(g)
139
byte[] hxg = Util.xor(hn, hg, 20);
140       if( log.isTraceEnabled() )
141          log.trace("H(N) xor H(g): "+Util.tob64(hxg));
142       clientHash.update(hxg);
143       if( log.isTraceEnabled() )
144       {
145          MessageDigest JavaDoc tmp = Util.copy(clientHash);
146          log.trace("H[H(N) xor H(g)]: "+Util.tob64(tmp.digest()));
147       }
148       // clientHash = H(N) xor H(g) | H(U)
149
clientHash.update(Util.newDigest().digest(username.getBytes()));
150       if( log.isTraceEnabled() )
151       {
152          MessageDigest JavaDoc tmp = Util.copy(clientHash);
153          log.trace("H[H(N) xor H(g) | H(U)]: "+Util.tob64(tmp.digest()));
154       }
155       // clientHash = H(N) xor H(g) | H(U) | s
156
clientHash.update(params.s);
157       if( log.isTraceEnabled() )
158       {
159          MessageDigest JavaDoc tmp = Util.copy(clientHash);
160          log.trace("H[H(N) xor H(g) | H(U) | s]: "+Util.tob64(tmp.digest()));
161       }
162       K = null;
163    }
164    
165    /**
166     * @returns The exponential residue (parameter A) to be sent to the server.
167     */

168    public byte[] exponential()
169    {
170       byte[] Abytes = null;
171       if(A == null)
172       {
173          /* If the random component of A has not been specified use a random
174          number */

175          if( a == null )
176          {
177             BigInteger JavaDoc one = BigInteger.ONE;
178             do
179             {
180                a = new BigInteger JavaDoc(A_LEN, Util.getPRNG());
181             } while(a.compareTo(one) <= 0);
182          }
183          A = g.modPow(a, N);
184          Abytes = Util.trim(A.toByteArray());
185          // clientHash = H(N) xor H(g) | H(U) | A
186
clientHash.update(Abytes);
187          if( log.isTraceEnabled() )
188          {
189             MessageDigest JavaDoc tmp = Util.copy(clientHash);
190             log.trace("H[H(N) xor H(g) | H(U) | s | A]: "+Util.tob64(tmp.digest()));
191          }
192          // serverHash = A
193
serverHash.update(Abytes);
194       }
195       return Abytes;
196    }
197    
198    /**
199     @returns M1 = H(H(N) xor H(g) | H(U) | s | A | B | K)
200     @exception NoSuchAlgorithmException thrown if the session key
201     MessageDigest algorithm cannot be found.
202     */

203    public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException JavaDoc
204    {
205       // clientHash = H(N) xor H(g) | H(U) | s | A | B
206
clientHash.update(Bbytes);
207       if( log.isTraceEnabled() )
208       {
209          MessageDigest JavaDoc tmp = Util.copy(clientHash);
210          log.trace("H[H(N) xor H(g) | H(U) | s | A | B]: "+Util.tob64(tmp.digest()));
211       }
212       // Calculate u as the first 32 bits of H(B)
213
byte[] hB = Util.newDigest().digest(Bbytes);
214       byte[] ub =
215       {hB[0], hB[1], hB[2], hB[3]};
216       // Calculate S = (B - g^x) ^ (a + u * x) % N
217
BigInteger JavaDoc B = new BigInteger JavaDoc(1, Bbytes);
218       if( log.isTraceEnabled() )
219          log.trace("B: "+Util.tob64(B.toByteArray()));
220       if( B.compareTo(v) < 0 )
221          B = B.add(N);
222       if( log.isTraceEnabled() )
223          log.trace("B': "+Util.tob64(B.toByteArray()));
224       if( log.isTraceEnabled() )
225          log.trace("v: "+Util.tob64(v.toByteArray()));
226       BigInteger JavaDoc u = new BigInteger JavaDoc(1, ub);
227       if( log.isTraceEnabled() )
228          log.trace("u: "+Util.tob64(u.toByteArray()));
229       BigInteger JavaDoc B_v = B.subtract(v);
230       if( log.isTraceEnabled() )
231          log.trace("B - v: "+Util.tob64(B_v.toByteArray()));
232       BigInteger JavaDoc a_ux = a.add(u.multiply(x));
233       if( log.isTraceEnabled() )
234          log.trace("a + u * x: "+Util.tob64(a_ux.toByteArray()));
235       BigInteger JavaDoc S = B_v.modPow(a_ux, N);
236       if( log.isTraceEnabled() )
237          log.trace("S: "+Util.tob64(S.toByteArray()));
238       // K = SessionHash(S)
239
MessageDigest JavaDoc sessionDigest = MessageDigest.getInstance(params.hashAlgorithm);
240       K = sessionDigest.digest(S.toByteArray());
241       if( log.isTraceEnabled() )
242          log.trace("K: "+Util.tob64(K));
243       // clientHash = H(N) xor H(g) | H(U) | A | B | K
244
clientHash.update(K);
245       byte[] M1 = clientHash.digest();
246       if( log.isTraceEnabled() )
247          log.trace("M1: H[H(N) xor H(g) | H(U) | s | A | B | K]: "+Util.tob64(M1));
248       serverHash.update(M1);
249       serverHash.update(K);
250       if( log.isTraceEnabled() )
251       {
252          MessageDigest JavaDoc tmp = Util.copy(serverHash);
253          log.trace("H[A | M1 | K]: "+Util.tob64(tmp.digest()));
254       }
255       return M1;
256    }
257    /**
258     * @param M2 The server's response to the client's challenge
259     * @returns True if and only if the server's response was correct.
260     */

261    public boolean verify(byte[] M2)
262    {
263       // M2 = H(A | M1 | K)
264
byte[] myM2 = serverHash.digest();
265       boolean valid = Arrays.equals(M2, myM2);
266       if( log.isTraceEnabled() )
267       {
268          log.trace("verify serverM2: "+Util.tob64(M2));
269          log.trace("verify M2: "+Util.tob64(myM2));
270       }
271       return valid;
272    }
273    
274    /** Returns the negotiated session K, K = SHA_Interleave(S)
275     @return the private session K byte[]
276     @throws SecurityException - if the current thread does not have an
277     getSessionKey SRPPermission.
278     */

279    public byte[] getSessionKey() throws SecurityException JavaDoc
280    {
281       SecurityManager JavaDoc sm = System.getSecurityManager();
282       if( sm != null )
283       {
284          SRPPermission p = new SRPPermission("getSessionKey");
285          sm.checkPermission(p);
286       }
287       return K;
288    }
289 }
290
Popular Tags