You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
5.5 KiB
167 lines
5.5 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement.Srp |
|
{ |
|
/** |
|
* Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe. |
|
* This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper |
|
* "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002" |
|
*/ |
|
public class Srp6Server |
|
{ |
|
protected BigInteger N; |
|
protected BigInteger g; |
|
protected BigInteger v; |
|
|
|
protected SecureRandom random; |
|
protected IDigest digest; |
|
|
|
protected BigInteger A; |
|
|
|
protected BigInteger privB; |
|
protected BigInteger pubB; |
|
|
|
protected BigInteger u; |
|
protected BigInteger S; |
|
protected BigInteger M1; |
|
protected BigInteger M2; |
|
protected BigInteger Key; |
|
|
|
public Srp6Server() |
|
{ |
|
} |
|
|
|
/** |
|
* Initialises the server to accept a new client authentication attempt |
|
* @param N The safe prime associated with the client's verifier |
|
* @param g The group parameter associated with the client's verifier |
|
* @param v The client's verifier |
|
* @param digest The digest algorithm associated with the client's verifier |
|
* @param random For key generation |
|
*/ |
|
public virtual void Init(BigInteger N, BigInteger g, BigInteger v, IDigest digest, SecureRandom random) |
|
{ |
|
this.N = N; |
|
this.g = g; |
|
this.v = v; |
|
|
|
this.random = random; |
|
this.digest = digest; |
|
} |
|
|
|
public virtual void Init(Srp6GroupParameters group, BigInteger v, IDigest digest, SecureRandom random) |
|
{ |
|
Init(group.N, group.G, v, digest, random); |
|
} |
|
|
|
/** |
|
* Generates the server's credentials that are to be sent to the client. |
|
* @return The server's public value to the client |
|
*/ |
|
public virtual BigInteger GenerateServerCredentials() |
|
{ |
|
BigInteger k = Srp6Utilities.CalculateK(digest, N, g); |
|
this.privB = SelectPrivateValue(); |
|
this.pubB = k.Multiply(v).Mod(N).Add(g.ModPow(privB, N)).Mod(N); |
|
|
|
return pubB; |
|
} |
|
|
|
/** |
|
* Processes the client's credentials. If valid the shared secret is generated and returned. |
|
* @param clientA The client's credentials |
|
* @return A shared secret BigInteger |
|
* @throws CryptoException If client's credentials are invalid |
|
*/ |
|
public virtual BigInteger CalculateSecret(BigInteger clientA) |
|
{ |
|
this.A = Srp6Utilities.ValidatePublicValue(N, clientA); |
|
this.u = Srp6Utilities.CalculateU(digest, N, A, pubB); |
|
this.S = CalculateS(); |
|
|
|
return S; |
|
} |
|
|
|
protected virtual BigInteger SelectPrivateValue() |
|
{ |
|
return Srp6Utilities.GeneratePrivateValue(digest, N, g, random); |
|
} |
|
|
|
private BigInteger CalculateS() |
|
{ |
|
return v.ModPow(u, N).Multiply(A).Mod(N).ModPow(privB, 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 virtual bool VerifyClientEvidenceMessage(BigInteger clientM1) |
|
{ |
|
// Verify pre-requirements |
|
if (this.A == null || this.pubB == 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 = Srp6Utilities.CalculateM1(digest, N, A, pubB, 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 virtual BigInteger CalculateServerEvidenceMessage() |
|
{ |
|
// 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 = Srp6Utilities.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 virtual BigInteger CalculateSessionKey() |
|
{ |
|
// 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 = Srp6Utilities.CalculateKey(digest, N, S); |
|
return Key; |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|