#define TRACE using System; using System.Diagnostics; using System.Globalization; using System.Numerics; using System.Security.Cryptography; using System.Text; using ArchestrAServices.Common; namespace ArchestrAServices.Contract; public class ClientAuthentication : EncryptionBase { private RNGCryptoServiceProvider m_Random = new RNGCryptoServiceProvider(); public ulong Timeout { get; set; } public ConnectionId connectionId { get; private set; } public bool SecureSessionEstablished { get; private set; } public string ReasonSecureSessionNotEstablished { get; private set; } public BigInteger ClientPrivateKey { get; private set; } public BigInteger ClientPublicKey { get; private set; } public BigInteger ServicePublicKey { get; private set; } public ClientAuthentication() { Reset(); ReasonSecureSessionNotEstablished = "Constructed"; base.DH_passphrase = Constants.GetDHPassphrase(); base.hashAlgorithm = Constants.hashAlgorithm; } public void EstablishSecureSession(string application, string domain, string host, MakeCallToServiceConnect ConnectDelegate, MakeCallToServiceActivate ActivateDelegate) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: EstablishSecureSession '{0}', '{1}', '{2}' entering", new object[3] { application, domain, host })); SecureSessionEstablished = false; InitializeAuthentication(); PublicKey clientToken = new PublicKey { ApplicationName = application, DomainName = domain, HostName = host, KeyValue = ClientPublicKey.ToByteArray() }; SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Sending Connect() with client public key of {0} bits", new object[1] { clientToken.KeyValue.Length * 8 })); Connection connection = default(Connection); ArchestrAResult archestrAResult = ConnectDelegate(out connection, application, domain, host, clientToken); if (archestrAResult.ErrorCode == EnumASBFactory.ArchestrAErrorToInt(ArchestrAError.Success)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Received successful response from service Connect() with service public key of {0} bits", new object[1] { connection.serviceKeyField.KeyValue.Length * 8 })); connectionId = connection.idField; ServicePublicKey = new BigInteger(connection.serviceKeyField.KeyValue); byte[] ClientValidationData = null; if (ProcessServiceNegotiation(connection.authenticationDataField.AuthenticationData, out ClientValidationData)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Returning client validation data in call to service ActivateSession()"); archestrAResult = ActivateDelegate(Authentication: new ConnectionAuthenticationData { AuthenticationData = ClientValidationData }, ConnectionId: connectionId, Timeout: Timeout); if (archestrAResult.ErrorCode == EnumASBFactory.ArchestrAErrorToInt(ArchestrAError.Success)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Service returned good result from ActivateSession(), secure session established")); SecureSessionEstablished = true; ReasonSecureSessionNotEstablished = "Secure session established"; } else { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Service returned bad result from ActivateSession(), no secure session established")); SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Service returned bad result from ActivateSession(), no secure session established")); SecureSessionEstablished = false; ReasonSecureSessionNotEstablished = $"Service ActivateSession() returned ArchestrAError '{EnumASBFactory.IntToArchestrAError(archestrAResult.ErrorCode).ToString()}'"; } } else { SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 100, "ClientAuth: Service validation data could not be verified, no secure session established"); SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, "ClientAuth: Service validation data could not be verified, no secure session established"); Reset(); SecureSessionEstablished = false; ReasonSecureSessionNotEstablished = "Service validation data returned from Connect() was invalid"; } } else { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Service returned bad result from Connect(), no secure session established"); SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, "ClientAuth: Service returned bad result from Connect(), no secure session established"); SecureSessionEstablished = false; ReasonSecureSessionNotEstablished = $"Service Connect() returned ArchestrAError '{EnumASBFactory.IntToArchestrAError(archestrAResult.ErrorCode).ToString()}'"; } } public void AbortSession() { Reset(); ReasonSecureSessionNotEstablished = "Session Aborted"; } public void DisconnectSecureSession(MakeCallToServiceDisconnect DisconnectDelegate) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Calling service Disconnect(), ending secure session"); DisconnectDelegate(connectionId); Reset(); ReasonSecureSessionNotEstablished = "Session Disconnected normally"; } private void Reset() { Timeout = 10000uL; connectionId = new ConnectionId { Id = default(Guid) }; SecureSessionEstablished = false; ReasonSecureSessionNotEstablished = "Reset"; ClientPrivateKey = BigInteger.MinusOne; ClientPublicKey = BigInteger.Zero; base.NegotiatedKey = new byte[200]; m_Random.GetBytes(base.NegotiatedKey); ServicePublicKey = BigInteger.Zero; } private void InitializeAuthentication() { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Generating D-H keys with size = {0}", new object[1] { Constants.DH_KeySize })); Constants.GenerateKey(Constants.DH_KeySize, out DH_p, out DH_g); BigInteger bigInteger = DH_p - new BigInteger(1); ClientPrivateKey = new BigInteger(0); while (ClientPrivateKey >= bigInteger || ClientPrivateKey <= 0L) { byte[] array = new byte[Constants.DH_SecretSize / 8]; m_Random.GetBytes(array); ClientPrivateKey = new BigInteger(array); } ClientPublicKey = BigInteger.ModPow(DH_g, ClientPrivateKey, DH_p); SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Generated Client private key and public key"); } private bool ProcessServiceNegotiation(byte[] ServiceValidationData, out byte[] ClientValidationData) { base.NegotiatedKey = Encoding.UTF8.GetBytes(base.DH_passphrase); SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, string.Format(CultureInfo.CurrentCulture, "ClientAuth: Computed negotiated key [{0} {1} {2} {3} .. {4} {5}] {6} bytes", base.NegotiatedKey[0], base.NegotiatedKey[1], base.NegotiatedKey[2], base.NegotiatedKey[3], base.NegotiatedKey[base.NegotiatedKey.Length - 2], base.NegotiatedKey[base.NegotiatedKey.Length - 1], base.NegotiatedKey.Length)); byte[] array = ServicePublicKey.ToByteArray(); byte[] array2 = ClientPublicKey.ToByteArray(); byte[] array3 = new byte[array.Length + array2.Length]; Array.Copy(array, array3, array.Length); Array.Copy(array2, 0, array3, array.Length, array2.Length); byte[] array4 = Decrypt(ServiceValidationData, base.NegotiatedKey); byte[] array5 = new byte[array4[0] + (array4[1] << 8)]; for (int i = 0; i < array5.Length; i++) { array5[i] = 0; } Array.Copy(array4, 2, array5, 0, array4.Length - 2); byte[] bytes = Encoding.UTF8.GetBytes(base.DH_passphrase); byte[] array6 = Decrypt(array5, bytes); byte[] array7 = new byte[array6[0] + (array6[1] << 8)]; for (int j = 0; j < array7.Length; j++) { array7[j] = 0; } Array.Copy(array6, 2, array7, 0, array6.Length - 2); bool flag = array3.Length == array7.Length; if (flag) { for (int k = 0; k < array7.Length; k++) { if (array3[k] != array7[k]) { flag = false; break; } } } bool flag2 = false; ClientValidationData = null; if (flag) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Decrypted and confirmed service validation data"); SecureSessionEstablished = true; ReasonSecureSessionNotEstablished = "Secure session established"; array3 = new byte[array2.Length + array.Length + 2]; int num = array3.Length - 2; array3[0] = (byte)((ulong)num & 0xFFuL); array3[1] = (byte)(((ulong)num >> 8) & 0xFF); Array.Copy(array2, 0, array3, 2, array2.Length); Array.Copy(array, 0, array3, array2.Length + 2, array.Length); byte[] array8 = Encrypt(array3, bytes); byte[] array9 = new byte[array8.Length + 2]; int num2 = array9.Length - 2; array9[0] = (byte)((ulong)num2 & 0xFFuL); array9[1] = (byte)(((ulong)num2 >> 8) & 0xFF); Array.Copy(array8, 0, array9, 2, array8.Length); ClientValidationData = Encrypt(array9, base.NegotiatedKey); SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Generated and encrypted return client validation data"); return true; } SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "ClientAuth: Service validation data is incorrect, cannot authenticate"); SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, "ClientAuth: Service validation data is incorrect, cannot authenticate"); SecureSessionEstablished = false; ReasonSecureSessionNotEstablished = "Service validation payload incorrect"; ClientValidationData = ServiceValidationData; return false; } }