/// <summary> /// Initiates the SRPP Request /// </summary> /// <param name="username">Username to login with</param> /// <param name="password">Password to login with</param> /// <param name="otherdata">Other data passed to LogonManager</param> /// <returns></returns> internal NetSRP.Request GenerateSRPRequest(String username, String password, Byte[] otherdata) { if ((this.HandshakeState != Handshake.State.NotInitialized) && (Handshake.State.AllowRequest & this.HandshakeState) != this.HandshakeState) { return(_request); // Already Created } if (username == null || password == null) { throw new NetSRP.HandShakeException("Need username and password to created SRP.Request"); } // Set state and timer this.HandshakeState = Handshake.State.Requesting; _cache.ExpirationTime = DateTime.Now.AddSeconds(Handshake.ExpirationInSeconds); // First get the public key A from random private a _cache.a = NetSRP.Geta(); _cache.A = NetSRP.CalcA(N, g, _cache.a); // Save the password to use when the response comes in _cache.UserData = password; // Create a new request _request = new NetSRP.Request(username, _cache.A, otherdata); return(_request); }
/// <summary> /// Actually verifies received verification data (initiated remotely) + generates response /// </summary> /// <param name="verification"></param> private NetSRP.Verification VerificationOfActiveParty(NetSRP.Verification verification) { if ((Handshake.State.AllowVerificating & this.HandshakeState) != this.HandshakeState) { return(_verification); // double } // Set State this.HandshakeState = Handshake.State.Verificating; // Hello I am the one that is being connected to. So let's generate // the value M I should have in the SRPPackedData Object. Byte[] M = NetSRP.CalcM(N, g, _request.Username, _response.Salt, _request.A, _cache.B, _cache.K); // Compare if (!NetUtility.ArraysEqual(M, verification.M)) { this.HandshakeState = Handshake.State.Denied | State.Failed; throw new NetSRP.HandShakeException("Invalid proof of Key. Username or password invalid.", new InvalidOperationException("Generated M does not match received M")); } // Ok, so their verification passed. Now let's proof that mine will to. _verification = new NetSRP.Verification(NetSRP.CalcM2(_request.A, verification.M, _cache.K)); // Check expiration (maybe use timer?) if (_cache.ExpirationTime.CompareTo(DateTime.Now) < 0) { this.HandshakeState = Handshake.State.Expired; throw new NetSRP.HandShakeException("Hand was not shaken before it expired."); } return(_verification); }
/// <summary> /// Actually verifies received verification data (initiated locally) /// </summary> /// <param name="verification"></param> private Boolean VerificationOfPassiveParty(NetSRP.Verification verification) { if ((Handshake.State.AllowVerification & this.HandshakeState) != this.HandshakeState) { return(false); } // Hello I am the one that tries to connect. So let's generate the // value M2 I should have in the SRPPackedData Object. Byte[] M2 = NetSRP.CalcM2(_cache.A, _verification.M, _cache.K); // Compare if (!NetUtility.ArraysEqual(M2, verification.M2)) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Username or password invalid.", new ArgumentException("Generated M2 does not match received M2")); } // Check expiration if (_cache.ExpirationTime.CompareTo(DateTime.Now) < 0) { this.HandshakeState = Handshake.State.Expired; throw new NetSRP.HandShakeException("Hand was not shaken before it expired."); } return(true); }
/// <summary> /// Generates Salt and Verifier for username and password /// </summary> /// <param name="username"></param> /// <param name="password"></param> /// <param name="keysize"></param> /// <param name="salt"></param> /// <returns></returns> public static NetBigInteger PasswordVerifier(String username, String password, Int32 keysize, out Byte[] salt) { salt = NetSRP.GenerateSalt(); NetBigInteger g, N = NetSRP.GetNandG(keysize, out g); return(NetSRP.PasswordVerifier(username, password, salt, N, g)); }
/// <summary> /// Create a response on received request. /// </summary> /// <param name="request">Receieved Request</param> /// <returns></returns> private NetSRP.Response ResponseFromRequest(NetSRP.Request request) { if (Handshake._defaultLogonManager == null) { throw new NetSRP.HandShakeException("No HandShake.Passive functions are available until LogonManager is provided."); } if (this.HandshakeState != Handshake.State.NotInitialized && (Handshake.State.AllowResponse & this.HandshakeState) != this.HandshakeState) { return(_response); } // Set State and start timer this.HandshakeState = Handshake.State.Responding; _cache.ExpirationTime = DateTime.Now.AddSeconds(Handshake.ExpirationInSeconds); if (request.A.Mod(N).IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Request contains invalid data", new ArgumentException("A mod N is zero.")); } Byte[] salt; NetBigInteger v; // Get verifier try { v = Lookup(request, out salt); } catch (Exception exception) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("LogonManager failed lookup.", exception); } if (v == null) { this.HandshakeState = Handshake.State.Denied; throw new NetSRP.HandShakeException("Wrong username or password."); // Clearly its username. } // Cache request _request = request; _cache.UserData = _request.Username; // Get public ket B from random private b _cache.b = NetSRP.Getb(); _cache.B = NetSRP.CalcB(N, g, _cache.b, v); // Create the response message _response = new NetSRP.Response(salt, _cache.B); // First create the key KeyFromRequest(request.A, v); return(_response); }
/// <summary> /// Generates key from request /// </summary> /// <param name="A">Generated A from request</param> /// <param name="v">Verifier v</param> private void KeyFromRequest(NetBigInteger A, NetBigInteger v) { // Shared random scrambler Lidgren.Network.NetBigInteger u = NetSRP.Calcu(A, _cache.B); // Sessionkey _cache.S = NetSRP.CalcSServer(N, A, v, u, _cache.b); _cache.K = NetSRP.CalcK(_cache.S); }
/// <summary> /// Generates Session key from response /// </summary> /// <param name="response"></param> /// <response></response> private NetSRP.Verification KeyFromResponse(NetSRP.Response response) { if ((Handshake.State.AllowVerificating & this.HandshakeState) != this.HandshakeState) { return(_verification); // Double Request } // When we get the response, get their public key B if (response.B.Mod(N).IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Response contains invalid data", new ArgumentException("B mod N is zero.")); } // Shared random scrambler NetBigInteger u = NetSRP.Calcu(_cache.A, response.B); if (u.IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Response contains invalid data", new ArgumentException("u is zero.")); } // Private key x NetBigInteger x = NetSRP.Calcx(response.Salt, _request.Username, _cache.UserData); // Cache Response; _response = response; // Session key _cache.S = NetSRP.CalcSClient(N, g, response.B, k, x, _cache.a, u); _cache.K = NetSRP.CalcK(_cache.S); // Create the verification _verification = new NetSRP.Verification(NetSRP.CalcM(N, g, _request.Username, response.Salt, _cache.A, response.B, _cache.K)); // Set State this.HandshakeState = Handshake.State.Verificating; return(_verification); }
/// <summary> /// Creates a new Handshake /// </summary> /// <param name="active">Is active party</param> /// <param name="keySize">keysize</param> /// <param name="logonManager">logonManager (only needed if passive)</param> internal Handshake(Boolean active, Int32 keySize, ILogonManager logonManager) { // Local Data setup _cache = new NetSRP.State(); _keySize = keySize; _logonManager = logonManager ?? _defaultLogonManager; if (!active && _defaultLogonManager == null) { _defaultLogonManager = logonManager; } // We calculate N and G for this insance. I choose to do so, so you can // have different keysizes throughout your program and are not stuck with one N = NetSRP.GetNandG(_keySize, out g); k = NetSRP.Calck(N, g); // Set as NotInitialized this.HandshakeState = Handshake.State.NotInitialized; if (!active && _logonManager == null) { throw new InvalidOperationException("Receiving handshakes need a logonManager"); } if (keySize == 0 || N == null || g == null || k == null) { throw new InvalidOperationException("Handshake not intialized"); } // NOTE: this is caused by the length of the hailmessage - larger then 4096 goes over the MTU if (keySize < 1024 || keySize > 4096) { throw new NetException("SRP6Keysize is not supported by Lidgren.Network", new ArgumentOutOfRangeException("keySize")); } }
/// <summary> /// Returns Verifier and Salt for request /// </summary> /// <param name="request">Request data</param> /// <param name="salt">salt output</param> /// <returns>verifier</returns> private NetBigInteger Lookup(NetSRP.Request request, out Byte[] salt) { return _logonManager.Lookup(request.Username, request.OtherData, out salt); }
/// <summary> /// Host stores v (password verifier) in database. /// </summary> /// <param name="userName"></param> /// <param name="password"></param> /// <param name="salt"></param> /// <param name="N"></param> /// <param name="g"></param> /// <returns></returns> public static NetBigInteger PasswordVerifier(String userName, String password, Byte[] salt, NetBigInteger N, NetBigInteger g) { NetBigInteger x = NetSRP.Calcx(salt, userName, password); return(NetSRP.CalcV(N, g, x)); }
/// <summary> /// Actually verifies received verification data (initiated locally) /// </summary> /// <param name="verification"></param> private Boolean VerificationOfPassiveParty(NetSRP.Verification verification) { if ((Handshake.State.AllowVerification & this.HandshakeState) != this.HandshakeState) return false; // Hello I am the one that tries to connect. So let's generate the // value M2 I should have in the SRPPackedData Object. Byte[] M2 = NetSRP.CalcM2(_cache.A, _verification.M, _cache.K); // Compare if (!NetUtility.ArraysEqual(M2, verification.M2)) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Username or password invalid.", new ArgumentException("Generated M2 does not match received M2")); } // Check expiration if (_cache.ExpirationTime.CompareTo(DateTime.Now) < 0) { this.HandshakeState = Handshake.State.Expired; throw new NetSRP.HandShakeException("Hand was not shaken before it expired."); } return true; }
/// <summary> /// Generates Session key from response /// </summary> /// <param name="response"></param> /// <response></response> private NetSRP.Verification KeyFromResponse(NetSRP.Response response) { if ((Handshake.State.AllowVerificating & this.HandshakeState) != this.HandshakeState) return _verification; // Double Request // When we get the response, get their public key B if (response.B.Mod(N).IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Response contains invalid data", new ArgumentException("B mod N is zero.")); } // Shared random scrambler NetBigInteger u = NetSRP.Calcu(_cache.A, response.B); if (u.IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Response contains invalid data", new ArgumentException("u is zero.")); } // Private key x NetBigInteger x = NetSRP.Calcx(response.Salt, _request.Username, _cache.UserData); // Cache Response; _response = response; // Session key _cache.S = NetSRP.CalcSClient(N, g, response.B, k, x, _cache.a, u); _cache.K = NetSRP.CalcK(_cache.S); // Create the verification _verification = new NetSRP.Verification(NetSRP.CalcM(N, g, _request.Username, response.Salt, _cache.A, response.B, _cache.K)); // Set State this.HandshakeState = Handshake.State.Verificating; return _verification; }
/// <summary> /// Create a response on received request. /// </summary> /// <param name="request">Receieved Request</param> /// <returns></returns> private NetSRP.Response ResponseFromRequest(NetSRP.Request request) { if (Handshake._defaultLogonManager == null) throw new NetSRP.HandShakeException("No HandShake.Passive functions are available until LogonManager is provided."); if (this.HandshakeState != Handshake.State.NotInitialized && (Handshake.State.AllowResponse & this.HandshakeState) != this.HandshakeState) return _response; // Set State and start timer this.HandshakeState = Handshake.State.Responding; _cache.ExpirationTime = DateTime.Now.AddSeconds(Handshake.ExpirationInSeconds); if (request.A.Mod(N).IntValue == 0) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("Request contains invalid data", new ArgumentException("A mod N is zero.")); } Byte[] salt; NetBigInteger v; // Get verifier try { v = Lookup(request, out salt); } catch (Exception exception) { this.HandshakeState = Handshake.State.Failed; throw new NetSRP.HandShakeException("LogonManager failed lookup.", exception); } if (v == null) { this.HandshakeState = Handshake.State.Denied; throw new NetSRP.HandShakeException("Wrong username or password."); // Clearly its username. } // Cache request _request = request; _cache.UserData = _request.Username; // Get public ket B from random private b _cache.b = NetSRP.Getb(); _cache.B = NetSRP.CalcB(N, g, _cache.b, v); // Create the response message _response = new NetSRP.Response(salt, _cache.B); // First create the key KeyFromRequest(request.A, v); return _response; }
/// <summary> /// Actually verifies received verification data (initiated remotely) + generates response /// </summary> /// <param name="verification"></param> private NetSRP.Verification VerificationOfActiveParty(NetSRP.Verification verification) { if ((Handshake.State.AllowVerificating & this.HandshakeState) != this.HandshakeState) return _verification; // double // Set State this.HandshakeState = Handshake.State.Verificating; // Hello I am the one that is being connected to. So let's generate // the value M I should have in the SRPPackedData Object. Byte[] M = NetSRP.CalcM(N, g, _request.Username, _response.Salt, _request.A, _cache.B, _cache.K); // Compare if (!NetUtility.ArraysEqual(M, verification.M)) { this.HandshakeState = Handshake.State.Denied | State.Failed; throw new NetSRP.HandShakeException("Invalid proof of Key. Username or password invalid.", new InvalidOperationException("Generated M does not match received M")); } // Ok, so their verification passed. Now let's proof that mine will to. _verification = new NetSRP.Verification(NetSRP.CalcM2(_request.A, verification.M, _cache.K)); // Check expiration (maybe use timer?) if (_cache.ExpirationTime.CompareTo(DateTime.Now) < 0) { this.HandshakeState = Handshake.State.Expired; throw new NetSRP.HandShakeException("Hand was not shaken before it expired."); } return _verification; }