1 package org.bouncycastle.crypto.agreement.srp;
2
3 import java.math.BigInteger;
4 import java.security.SecureRandom;
5
6 import org.bouncycastle.crypto.CryptoException;
7 import org.bouncycastle.crypto.Digest;
8
9 /**
10 * Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
11 * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
12 * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
13 */
14 public class SRP6Server
15 {
16 protected BigInteger N;
17 protected BigInteger g;
18 protected BigInteger v;
19
20 protected SecureRandom random;
21 protected Digest digest;
22
23 protected BigInteger A;
24
25 protected BigInteger b;
26 protected BigInteger B;
27
28 protected BigInteger u;
29 protected BigInteger S;
30
31 public SRP6Server()
32 {
33 }
34
35 /**
36 * Initialises the server to accept a new client authentication attempt
37 * @param N The safe prime associated with the client's verifier
38 * @param g The group parameter associated with the client's verifier
39 * @param v The client's verifier
40 * @param digest The digest algorithm associated with the client's verifier
41 * @param random For key generation
42 */
43 public void init(BigInteger N, BigInteger g, BigInteger v, Digest digest, SecureRandom random)
44 {
45 this.N = N;
46 this.g = g;
47 this.v = v;
48
49 this.random = random;
50 this.digest = digest;
51 }
52
53 /**
54 * Generates the server's credentials that are to be sent to the client.
55 * @return The server's public value to the client
56 */
57 public BigInteger generateServerCredentials()
58 {
59 BigInteger k = SRP6Util.calculateK(digest, N, g);
60 this.b = selectPrivateValue();
61 this.B = k.multiply(v).mod(N).add(g.modPow(b, N)).mod(N);
62
63 return B;
64 }
65
66 /**
67 * Processes the client's credentials. If valid the shared secret is generated and returned.
68 * @param clientA The client's credentials
69 * @return A shared secret BigInteger
70 * @throws CryptoException If client's credentials are invalid
71 */
72 public BigInteger calculateSecret(BigInteger clientA) throws CryptoException
73 {
74 this.A = SRP6Util.validatePublicValue(N, clientA);
75 this.u = SRP6Util.calculateU(digest, N, A, B);
76 this.S = calculateS();
77
78 return S;
79 }
80
81 protected BigInteger selectPrivateValue()
82 {
83 return SRP6Util.generatePrivateValue(digest, N, g, random);
84 }
85
86 private BigInteger calculateS()
87 {
88 return v.modPow(u, N).multiply(A).mod(N).modPow(b, N);
89 }
90 }