/// <summary> /// The identity exchanged event args constructor; contains the identity and Asymmetric parameters OId from an Identity structure /// </summary> /// /// <param name="Message">The <see cref="DtmServiceFlags"/> (Auth or Primary), from which this message originated</param> /// <param name="Flag">An option flag that contains the clients Asymmetric parameters OId</param> /// <param name="DtmID">The <see cref="DtmIdentity"/> containing identity and session parameters</param> public DtmIdentityEventArgs(DtmExchangeFlags Message, long Flag, DtmIdentity DtmID) { this.Message = Message; this.Flag = Flag; this.DtmID = DtmID; this.Cancel = false; }
/// <summary> /// Initialize this class with a random generator /// </summary> /// /// <param name="Parameters">A populated <see cref="DtmParameters"/> class containing the session parameters</param> /// <param name="Host">A populated <see cref="DtmClient"/> class containing the servers identity data</param> /// <param name="Generator">The initialized <see cref="IRandom"/> Prng instance</param> /// <param name="BufferCount">The number of send/receive buffers, default is 1024</param> /// <param name="DisposeEngines">if set to true (default), the primary symmetric ciphers are disposed when this class is disposed</param> public DtmKex(DtmParameters Parameters, DtmClient Host, IRandom Generator, int BufferCount = 1024, bool DisposeEngines = true) { _disposeEngines = DisposeEngines; _dtmParameters = Parameters; _dtmHost = Host; _srvIdentity = new DtmIdentity(Host.PublicId, Parameters.AuthPkeId, Parameters.AuthSession, 0); _exchangeState = DtmExchangeFlags.Connect; _rcvBuffer = new PacketBuffer(BufferCount); _sndBuffer = new PacketBuffer(BufferCount); _rndGenerator = Generator; _bufferCount = BufferCount; }
/// <summary> /// Process the clients identity structure <see cref="DtmIdentity"/>. /// </summary> /// /// <param name="PacketStream">A Stream containing the raw packet data</param> private void ProcessSync(MemoryStream PacketStream) { // get the header DtmPacket pktHdr = new DtmPacket(PacketStream); // read the data byte[] data = new byte[pktHdr.PayloadLength]; PacketStream.Read(data, 0, data.Length); // use clients symmetric key to decrypt data byte[] dec = SymmetricTransform(_cltSymProcessor, data); // remove random padding dec = UnwrapMessage(dec); // get the identity _cltIdentity = new DtmIdentity(dec); // pass id to the client, include oid long resp = 0; if (IdentityReceived != null) { DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Init, _cltIdentity.OptionFlag, _cltIdentity); IdentityReceived(this, args); resp = args.Flag; if (args.Cancel) { // back out of session TearDown(); } } // get the params oid _cltAsmParams = GetAsymmetricParams(_cltIdentity.PkeId); }
/// <summary> /// Processes the clients public identity and clients Auth-Stage PKE parameter set Id; <see cref="IAsymmetricParameters"/>. /// <para>Process the clients Auth-Stage public identity structure; <see cref="DtmIdentity"/></para> /// </summary> /// /// <param name="PacketStream">A Stream containing the raw packet data</param> /// /// <remarks>Fires the <see cref="IdentityReceived"/> event; returning the <see cref="DtmIdentityEventArgs"/> object containing the clients public id structure. /// <para>The session can be aborted by setting the DtmIdentityEventArgs Cancel flag to true.</para> /// </remarks> private void ProcessInit(MemoryStream PacketStream) { // seek past header PacketStream.Seek(DtmPacket.GetHeaderSize(), SeekOrigin.Begin); // get the clients id structure _cltIdentity = new DtmIdentity(PacketStream); // get client asymmetric params _cltAsmParams = GetAsymmetricParams(_cltIdentity.PkeId); // store the auth session _cltAuthSession = _cltIdentity.Session; // pass it to the client again, so it can be refused on basis of params long resp = 0; if (IdentityReceived != null) { DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Init, 0, _cltIdentity); IdentityReceived(this, args); resp = args.Flag; if (args.Cancel) { // back out of session TearDown(); } } }
/// <summary> /// Processes the clients public identity field for preliminary authentication. /// <para>Process the clients partial Auth-Stage public identity structure; <see cref="DtmIdentity"/></para> /// </summary> /// /// <param name="PacketStream">A Stream containing the raw packet data</param> /// /// <remarks> /// The client auto-negotiates to the security level of the server (the host accepting the connection request). /// Fires the <see cref="IdentityReceived"/> event; returning the <see cref="DtmIdentityEventArgs"/> object containing the clients public id structure. /// <para>The session can be aborted by setting the DtmIdentityEventArgs Cancel flag to true.</para> /// </remarks> private void ProcessConnect(MemoryStream PacketStream) { // seek past header PacketStream.Seek(DtmPacket.GetHeaderSize(), SeekOrigin.Begin); // get the clients id structure _cltIdentity = new DtmIdentity(PacketStream); // pass it to the client, evaluate the id if (IdentityReceived != null) { DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Init, 0, _cltIdentity); IdentityReceived(this, args); if (args.Cancel) { // back out of session TearDown(); } } // synchronize security level with the server if (!_isServer) { // get the servers security context and compare it to ours DtmParamSets.SecurityContexts srvSec = (DtmParamSets.SecurityContexts)_cltIdentity.OptionFlag; DtmParamSets.SecurityContexts cltSec = DtmParamSets.GetContext(_dtmParameters.OId); if (cltSec != srvSec) { // match servers security parameters if (!NegotiateSecurity(srvSec)) { // the negotiation failed Disconnect(); } } } }
/// <summary> /// Process the clients private identity. /// <para>Decrypts and stores the clients private identity using the clients Auth-Stage Symmetric Key.</para> /// </summary> /// /// <param name="PacketStream">A Stream containing the raw packet data</param> private void ProcessAuth(MemoryStream PacketStream) { // get the header DtmPacket pktHdr = new DtmPacket(PacketStream); byte[] data = new byte[pktHdr.PayloadLength]; PacketStream.Read(data, 0, data.Length); // create the clients auth-stage symmetric cipher _cltSymProcessor = SymmetricInit(_cltIdentity.Session, _cltKeyParams); // decrypt the payload byte[] dec = SymmetricTransform(_cltSymProcessor, data); // remove random padding dec = UnwrapMessage(dec); // get the clients private id _cltIdentity = new DtmIdentity(new MemoryStream(dec)); // notify user long resp = 0; if (IdentityReceived != null) { DtmIdentityEventArgs args = new DtmIdentityEventArgs(DtmExchangeFlags.Auth, resp, _cltIdentity); IdentityReceived(this, args); resp = args.Flag; if (args.Cancel) { // back out of session TearDown(); } } }
/// <summary> /// The remote server requires security parameters negotiation to continue. /// <para>Evaluates the requested security parameter requirement from a server, /// using the security context stored in the servers identity structure option flag.</para> /// </summary> /// /// <param name="Context">The servers required security level</param> /// /// <returns>Returns true if the negotiation succeeds</returns> private bool NegotiateSecurity(DtmParamSets.SecurityContexts Context) { // get the clients id structure DtmParamSets.SecurityContexts sxt = DtmParamSets.GetContext(_dtmParameters.OId); // note: only negotiate up as a security measure? if (Context == DtmParamSets.SecurityContexts.X1) _dtmParameters = (DtmParameters)DtmParamSets.DTMX11RNS1R2.DeepCopy(); else if (Context == DtmParamSets.SecurityContexts.X2) _dtmParameters = (DtmParameters)DtmParamSets.DTMX22MNS2R2.DeepCopy(); else if (Context == DtmParamSets.SecurityContexts.X3) _dtmParameters = (DtmParameters)DtmParamSets.DTMX31RNT1R2.DeepCopy(); else if (Context == DtmParamSets.SecurityContexts.X4) _dtmParameters = (DtmParameters)DtmParamSets.DTMX41RNT1R1.DeepCopy(); else return false; // error or failure // copy new security params _srvIdentity = new DtmIdentity(_dtmHost.PublicId, _dtmParameters.AuthPkeId, _dtmParameters.AuthSession, 0); return true; }
/// <summary> /// Send the servers Primary-Stage session parameters in a <see cref="DtmIdentity"/> structure. /// <para>The packet header; <see cref="DtmPacket"/>, contains the message type, payload length, sequence number, and exchange state. /// The payload is the servers identity structure (DtmIdentity), containing the secret id field, the session key parameters <see cref="DtmSession"/>, and the /// primary-stage PKE parameters Id.</para> /// </summary> /// /// <returns>A raw packet containing the packet header, and the servers private identity</returns> private MemoryStream CreateSync() { // change to primary parameters _srvIdentity = new DtmIdentity(_dtmHost.SecretId, _dtmParameters.PrimaryPkeId, _dtmParameters.PrimarySession, 0); // serialize identity byte[] data = _srvIdentity.ToBytes(); // wrap the id with random data = WrapMessage(data, _dtmParameters.MaxMessageAppend, _dtmParameters.MaxMessagePrePend); // encrypt with servers session key byte[] enc = SymmetricTransform(_srvSymProcessor, data); // payload container MemoryStream pldStm = new MemoryStream(enc); // stage completed _exchangeState = DtmExchangeFlags.Sync; return pldStm; }
// Functions are in order of execution. The Create functions create a response packet, the Process functions process the result. /// <summary> /// Send the servers partial public identity structure <see cref="DtmIdentity"/>. /// <para>The packet header; <see cref="DtmPacket"/>, contains the message type, payload length, sequence number, and exchange state. /// The payload is the servers public identity field in a default DtmIdentity structure.</para> /// </summary> /// /// <param name="Trust">The level of trust expected (for future use)</param> /// /// <returns>A raw packet containing the packet header, and the servers public identity structure</returns> private MemoryStream CreateConnect(DtmTrustStates Trust = DtmTrustStates.None) { // the option flag is used to describe minimum security level required from this instance int sec = (int)DtmParamSets.GetContext(_dtmParameters.OId); // create a partial id and add auth asymmetric and session params. MemoryStream sid = new DtmIdentity(_srvIdentity.Identity, new byte[] { 0, 0, 0, 0 }, new DtmSession(), sec).ToStream(); // stage completed _exchangeState = DtmExchangeFlags.Connect; return sid; }
/// <summary> /// Serialize a <see cref="DtmIdentity"/> structure /// </summary> /// /// <param name="Identity">A DtmIdentity structure</param> /// /// <returns>A stream containing the DtmIdentity data</returns> public static Stream Serialize(DtmIdentity Identity) { return Identity.ToStream(); }