diff options
author | David Hook <dgh@cryptoworkshop.com> | 2014-06-21 08:52:29 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2014-06-21 08:52:29 +0400 |
commit | ab148cdaa8635ae154e75ce22fa70925f9a11f5a (patch) | |
tree | 9e72617e4f262e1d68a74954e0d52547889c86a4 /core/src/main/java | |
parent | 18fa0dc31184b070c067ddbc8a0c37aedf6d68c5 (diff) | |
parent | 1d4caab51e298a21a56aea817815c1a63947e1f7 (diff) |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'core/src/main/java')
3 files changed, 180 insertions, 2 deletions
diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Client.java b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Client.java index 4df90236..153e5a83 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Client.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Client.java @@ -25,6 +25,10 @@ public class SRP6Client protected BigInteger u; protected BigInteger S; + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; + protected Digest digest; protected SecureRandom random; @@ -64,7 +68,7 @@ public class SRP6Client } /** - * Generates client's verification message given the server's credentials + * Generates the secret S given the server's credentials * @param serverB The server's credentials * @return Client's verification message for the server * @throws CryptoException If server's credentials are invalid @@ -90,4 +94,57 @@ public class SRP6Client BigInteger tmp = g.modPow(x, N).multiply(k).mod(N); return B.subtract(tmp).mod(N).modPow(exp, N); } + + /** + * Computes the client evidence message M1 using the previously received values. + * To be called after calculating the secret S. + * @return M1: the client side generated evidence message + * @throws CryptoException + */ + public BigInteger calculateClientEvidenceMessage() throws CryptoException{ + // verify pre-requirements + if ((this.A==null)||(this.B==null)||(this.S==null)){ + throw new CryptoException("Impossible to compute M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + // compute the client evidence message 'M1' + this.M1 = SRP6Util.calculateM1(digest, N, A, B, S); + return M1; + } + + /** Authenticates the server evidence message M2 received and saves it only if correct. + * @param M2: the server side generated evidence message + * @return A boolean indicating if the server message M2 was the expected one. + * @throws CryptoException + */ + public boolean verifyServerEvidenceMessage(BigInteger serverM2) throws CryptoException{ + //verify pre-requirements + if ((this.A==null)||(this.M1==null)||(this.S==null)){ + throw new CryptoException("Impossible to compute and verify M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + // Compute the own server evidence message 'M2' + BigInteger computedM2 = SRP6Util.calculateM2(digest, N, A, M1, S); + if (computedM2.equals(serverM2)){ + this.M2 = serverM2; + return true; + } + return false; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after verifying the server evidence message M2. + * @return Key: the mutually authenticated symmetric session key + * @throws CryptoException + */ + public BigInteger calculateSessionKey() throws CryptoException{ + //verify pre-requirements (here we enforce a previous calculation of M1 and M2) + if ((this.S==null)||(this.M1==null)||(this.M2==null)){ + throw new CryptoException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = SRP6Util.calculateKey(digest, N, S); + return Key; + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Server.java b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Server.java index fb208388..5d703470 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Server.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Server.java @@ -27,7 +27,10 @@ public class SRP6Server protected BigInteger u; protected BigInteger S; - + protected BigInteger M1; + protected BigInteger M2; + protected BigInteger Key; + public SRP6Server() { } @@ -87,4 +90,59 @@ public class SRP6Server { return v.modPow(u, N).multiply(A).mod(N).modPow(b, N); } + + /** + * Authenticates the received client evidence message M1 and saves it only if correct. + * To be called after calculating the secret S. + * @param M1: the client side generated evidence message + * @return A boolean indicating if the client message M1 was the expected one. + * @throws CryptoException + */ + public boolean verifyClientEvidenceMessage(BigInteger clientM1) throws CryptoException{ + //verify pre-requirements + if ((this.A==null)||(this.B==null)||(this.S==null)){ + throw new CryptoException("Impossible to compute and verify M1: " + + "some data are missing from the previous operations (A,B,S)"); + } + // Compute the own client evidence message 'M1' + BigInteger computedM1 = SRP6Util.calculateM1(digest, N, A, B, S); + if (computedM1.equals(clientM1)){ + this.M1 = clientM1; + return true; + } + return false; + } + + /** + * Computes the server evidence message M2 using the previously verified values. + * To be called after successfully verifying the client evidence message M1. + * @return M2: the server side generated evidence message + * @throws CryptoException + */ + public BigInteger calculateServerEvidenceMessage() throws CryptoException{ + //verify pre-requirements + if ((this.A==null)||(this.M1==null)||(this.S==null)){ + throw new CryptoException("Impossible to compute M2: " + + "some data are missing from the previous operations (A,M1,S)"); + } + // Compute the server evidence message 'M2' + this.M2 = SRP6Util.calculateM2(digest, N, A, M1, S); + return M2; + } + + /** + * Computes the final session key as a result of the SRP successful mutual authentication + * To be called after calculating the server evidence message M2. + * @return Key: the mutual authenticated symmetric session key + * @throws CryptoException + */ + public BigInteger calculateSessionKey() throws CryptoException{ + //verify pre-requirements + if ((this.S==null)||(this.M1==null)||(this.M2==null)){ + throw new CryptoException("Impossible to compute Key: " + + "some data are missing from the previous operations (S,M1,M2)"); + } + this.Key = SRP6Util.calculateKey(digest, N, S); + return Key; + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Util.java b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Util.java index ad5ceac8..6bcf0183 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Util.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/srp/SRP6Util.java @@ -60,6 +60,69 @@ public class SRP6Util return val; } + /** + * Computes the client evidence message (M1) according to the standard routine: + * M1 = H( A | B | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param B The public server value + * @param S The secret calculated by both sides + * @return M1 The calculated client evidence message + */ + public static BigInteger calculateM1(Digest digest, BigInteger N, BigInteger A, BigInteger B, BigInteger S) { + BigInteger M1 = hashPaddedTriplet(digest,N,A,B,S); + return M1; + } + + /** + * Computes the server evidence message (M2) according to the standard routine: + * M2 = H( A | M1 | S ) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param A The public client value + * @param M1 The client evidence message + * @param S The secret calculated by both sides + * @return M2 The calculated server evidence message + */ + public static BigInteger calculateM2(Digest digest, BigInteger N, BigInteger A, BigInteger M1, BigInteger S){ + BigInteger M2 = hashPaddedTriplet(digest,N,A,M1,S); + return M2; + } + + /** + * Computes the final Key according to the standard routine: Key = H(S) + * @param digest The Digest used as the hashing function H + * @param N Modulus used to get the pad length + * @param S The secret calculated by both sides + * @return + */ + public static BigInteger calculateKey(Digest digest, BigInteger N, BigInteger S) { + int padLength = (N.bitLength() + 7) / 8; + byte[] _S = getPadded(S,padLength); + digest.update(_S, 0, _S.length); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + return new BigInteger(1, output); + } + + private static BigInteger hashPaddedTriplet(Digest digest, BigInteger N, BigInteger n1, BigInteger n2, BigInteger n3){ + int padLength = (N.bitLength() + 7) / 8; + + byte[] n1_bytes = getPadded(n1, padLength); + byte[] n2_bytes = getPadded(n2, padLength); + byte[] n3_bytes = getPadded(n3, padLength); + + digest.update(n1_bytes, 0, n1_bytes.length); + digest.update(n2_bytes, 0, n2_bytes.length); + digest.update(n3_bytes, 0, n3_bytes.length); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + + return new BigInteger(1, output); + } private static BigInteger hashPaddedPair(Digest digest, BigInteger N, BigInteger n1, BigInteger n2) { |