Inheritance: MonoBehaviour
Esempio n. 1
0
        public void TestClone()
        {
            var message = "hello, how are you good sir?";

            var s1 = new Strobe("myHash", 128);
            var s2 = s1.Clone() as Strobe;

            s1.Operate(false, Operation.Ad, Encoding.ASCII.GetBytes(message), 0, false);
            var state1  = s1.DebugPrintState();
            var out1    = s1.Prf(32).ToHexString();
            var state12 = s1.DebugPrintState();

            s2.Operate(false, Operation.Ad, Encoding.ASCII.GetBytes(message), 0, false);
            var state2  = s2.DebugPrintState();
            var out2    = s2.Prf(32).ToHexString();
            var state22 = s2.DebugPrintState();

            System.Diagnostics.Debug.WriteLine(out1);
            System.Diagnostics.Debug.WriteLine(out2);

            if (out1 != out2 || state1 != state2 || state12 != state22)
            {
                throw new Exception("strobe cannot stream correctly");
            }
        }
Esempio n. 2
0
        public void TestStream2()
        {
            var s = new Strobe("custom string number 2, that's a pretty long string", 128);

            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            var key = Encoding.ASCII.GetBytes("0101010100100101010101010101001001");

            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            s.Operate(false, Operation.Key, key, 0, false);
            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            s.Operate(false, Operation.Key, key, 0, true);
            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            var message = Encoding.ASCII.GetBytes(("hello, how are you good sir? ????"));

            s.Operate(false, Operation.Ad, message, 0, false);
            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            s.Operate(false, Operation.Ad, message, 0, true);
            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());
            s.Operate(false, Operation.Ad, message, 0, false);
            System.Diagnostics.Debug.WriteLine(s.DebugPrintState());

            if (!string.Equals(s.DebugPrintState(), "5117b46c2d842655c1be2a69f64f16aaaad2c0050fe2ac5446afe44345a9b10d0"
                               + "44c8b3ec8005a9e362c0a431ab5c4d8228c2f890ae56ad3fef4404aa6cc76704b503d627553ae9635d329c"
                               + "dfa86ed29ec0dd79787ff3fcefdee7463c053ef3b4a4fa7c8eb89a6372df2c4ccfc7469d7447bd19a67940"
                               + "642334706e5ff6b1ef58514e55c6b5c6921c58eb7cb5c57978c92c42e598926fcfdcd9705fb948ed6fe902"
                               + "7c65fb0659c98a9c9668d523dfa2b27bde76224944503b686901c989fedac34994dd16daedf00", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new Exception("this is not working");
            }
        }
Esempio n. 3
0
        public Strobe TranscriptCommit(string sth, byte[] message)
        {
            var obj = new Strobe("Merlin", 128);

            obj.Ad(true, message);
            return(obj);
        }
Esempio n. 4
0
 public static void SetStrobe(Light l, Strobe s)
 {
     if (l == Light.LIGHT1)
     {
         LightThread.Light1.StrobeVal = s;
     }
     if (l == Light.LIGHT2)
     {
         LightThread.Light2.StrobeVal = s;
     }
 }
Esempio n. 5
0
 public static void SetAll(Light l, Color c, Gobo g, Strobe s, Int32 pan, Int32 panf, Int32 tilt, Int32 tiltf)
 {
     LightOnOff(l, true);
     SetColor(l, c);
     SetGobo(l, g);
     SetStrobe(l, s);
     SetPan(l, pan);
     SetPanFine(l, panf);
     SetTilt(l, tilt);
     SetTiltFine(l, tiltf);
 }
Esempio n. 6
0
        /// <summary>
        /// Output (extract) data from strobe state
        /// </summary>
        /// <param name="outputLength">Expected output length</param>
        public Hash(int outputLength)
        {
            if (outputLength < Symmetric.HashSize)
            {
                throw new Exception(
                          $"disco: an output length smaller than {Symmetric.HashSize*8}-bit " +
                          $"({Symmetric.HashSize} bytes) has security consequences");
            }

            this.strobeState = new Strobe("DiscoHash", Symmetric.SecurityParameter);
            this.outputLen   = outputLength;
        }
Esempio n. 7
0
        static void Main()
        {
            // Create strobe object, setting init string and security
            var strobe = new Strobe("MyStrobe", 128);

            var messageByte = Encoding.ASCII.GetBytes("Hello gentlemens");

            strobe.Ad(false, messageByte);

            var prfBytes = strobe.Prf(16);

            Console.WriteLine(BitConverter.ToString(prfBytes).Replace("-", ""));
        }
Esempio n. 8
0
        /// <summary>
        /// Hash allows you to hash an input of any length and obtain an output
        /// of length greater or equal to 256 bits (32 bytes).
        /// </summary>
        /// <returns>Resulted Hash</returns>
        public static byte[] Hash(byte[] input, int outputLength)
        {
            if (outputLength < Symmetric.HashSize)
            {
                throw new Exception(
                          $"discoNet: an output length smaller than {Symmetric.HashSize*8}-bit " +
                          $"({Symmetric.HashSize} bytes) has security consequences");
            }

            var hash = new Strobe("DiscoHash", Symmetric.SecurityParameter);

            hash.Ad(false, input);
            return(hash.Prf(outputLength));
        }
Esempio n. 9
0
        private void RunTestVector(string vectorName)
        {
            var vector = this.TestVectors.TestVectors.Find(tv => tv.Name == vectorName);

            Strobe strobe = null;

            foreach (var operation in vector.Operations)
            {
                if (operation.Name == "init")
                {
                    strobe = new Strobe(operation.CustomString, operation.Security);
                    if (!string.Equals(
                            strobe.DebugPrintState(),
                            operation.StateAfter,
                            StringComparison.InvariantCultureIgnoreCase))
                    {
                        throw new Exception();
                    }

                    continue;
                }

                if (strobe == null)
                {
                    throw new ArgumentNullException(nameof(strobe));
                }

                var result = strobe.Operate(
                    operation.Meta ?? false,
                    operation.GetStrobeOperation(),
                    operation.InputData?.ToByteArray(),
                    operation.InputLength,
                    operation.Stream ?? false);
                if (!string.Equals(
                        strobe.DebugPrintState(),
                        operation.StateAfter,
                        StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new Exception();
                }

                if (operation.Output != null && !string.Equals(
                        operation.Output,
                        result.ToHexString(),
                        StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new Exception();
                }
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Derive key data
        /// </summary>
        /// <param name="keyMaterial">Derivation material</param>
        /// <param name="keyLen">Length of expected output</param>
        /// <returns>Derived data</returns>
        public static byte[] DeriveKeys(byte[] keyMaterial, int keyLen)
        {
            if (keyMaterial.Length < Symmetric.KeySize)
            {
                throw new Exception(
                          $"disco: deriving keys from a value smaller than {Symmetric.KeySize * 8}-bit "
                          + $"({Symmetric.KeySize} bytes) has security consequences");
            }

            var hash = new Strobe("DiscoKDF", Symmetric.SecurityParameter);

            hash.Ad(false, keyMaterial);
            return(hash.Prf(keyLen));
        }
Esempio n. 11
0
        /// <summary>
        /// Protect integrity of unencrypted text
        /// </summary>
        /// <param name="key">Symmetric key for MAC</param>
        /// <param name="plaintext">Plaintext to protect</param>
        /// <returns>Plaintext with MAC tag</returns>
        public static byte[] ProtectIntegrity(byte[] key, byte[] plaintext)
        {
            if (key.Length < Symmetric.KeySize)
            {
                throw new Exception(
                          $"disco: using a key smaller than {Symmetric.KeySize * 8}-bit "
                          + $"({Symmetric.KeySize} bytes) has security consequences");
            }

            var hash = new Strobe("DiscoMAC", Symmetric.SecurityParameter);

            hash.Ad(false, key);
            hash.Ad(false, plaintext);
            return(plaintext.Concat(hash.SendMac(false, Symmetric.TagSize)).ToArray());
        }
Esempio n. 12
0
        /// <summary>
        /// Encrypt a plaintext message with a key of any size greater than 128 bits (16 bytes).
        /// </summary>
        /// <param name="key">
        /// Symmetric key for encryption
        /// </param>
        /// <param name="plaintext">
        /// Plaintext to encrypt
        /// </param>
        /// <returns>Encrypted data</returns>
        public static byte[] Encrypt(byte[] key, byte[] plaintext)
        {
            if (key.Length < Symmetric.KeySize)
            {
                throw new Exception(
                          $"disco: using a key smaller than {Symmetric.KeySize * 8}-bit " +
                          $"({Symmetric.KeySize} bytes) has security consequences");
            }

            var ae = new Strobe("DiscoAE", Symmetric.SecurityParameter);

            // Absorb the key
            ae.Ad(false, key);

            // Generate 192-bit nonce
            var random = new RNGCryptoServiceProvider();
            var nonce  = new byte[Symmetric.NonceSize];

# if !DEBUG_DETERMINISTIC
Esempio n. 13
0
    // place a light with a ceiling floor or wall
    void placeLight(GameObject obj, int y, int z, float brightness, string inColor, float time)
    {
        Vector3 spawnPosition = new Vector3(0, (y * spawnOffset) + transform.position.y, (z * spawnOffset) + transform.position.z);

        GameObject outObj = Instantiate(obj, spawnPosition, Quaternion.identity);
        Strobe     strobe = outObj.GetComponent <Strobe>();

        Color outColor = new Color();

        switch (inColor)
        {
        case "g":
            outColor.r = 0;
            outColor.g = 255;
            outColor.b = 0;
            break;

        case "r":
            outColor.r = 255;
            outColor.g = 0;
            outColor.b = 0;
            break;

        case "b":
            outColor.r = 0;
            outColor.g = 0;
            outColor.b = 255;
            break;

        default:
            outColor.r = 255;
            outColor.g = 255;
            outColor.b = 255;
            break;
        }

        strobe.StrobeTime   = time;
        strobe.intensityMax = brightness;
        strobe.color        = outColor;
    }
Esempio n. 14
0
        private bool handleStrobeValue(HALHandleContext ctx)
        {
            Strobe t = ctx.Value as Strobe;

            if (t == null)
            {
                return(false);
            }

            this._lastStrobeContext = ctx;
            if (this._strobeEmulator == null)
            {
                this._strobeEmulator            = new StrobeEmulator("RGB-Color-Strobe");
                this._strobeEmulator.StrobeOff += handleEmulatorStrobeOff;
                this._strobeEmulator.StrobeOn  += handleEmulatorStrobeOn;
            }

            this.StrobeValue = t.Speed;

            ctx.AddHandleBag(new PropertyValueHandleBag(ctx.Property, (Strobe)this.StrobeValue, this.HandlerName, this.getDependencies()));
            return(true);
        }
Esempio n. 15
0
        /// <summary>
        /// Retrieve and Verify plaintext from unencrypted message
        /// </summary>
        /// <param name="key">
        /// Symmetric MAC key
        /// </param>
        /// <param name="plaintextAndTag">
        /// Plaintext with MAC tag to verify
        /// </param>
        /// <returns>Plaintext</returns>
        public static byte[] VerifyIntegrity(byte[] key, byte[] plaintextAndTag)
        {
            if (key.Length < Symmetric.KeySize)
            {
                throw new Exception(
                          $"disco: using a key smaller than {Symmetric.KeySize * 8}-bit "
                          + $"({Symmetric.KeySize} bytes) has security consequences");
            }

            if (plaintextAndTag.Length < Symmetric.TagSize)
            {
                throw new Exception("disco: plaintext does not contain an integrity tag");
            }

            var plainTextLen = plaintextAndTag.Length - Symmetric.TagSize;
            var plainText    = new byte[plainTextLen];

            Array.Copy(plaintextAndTag, 0, plainText, 0, plainTextLen);

            var tag = new byte[Symmetric.TagSize];

            Array.Copy(plaintextAndTag, plainTextLen, tag, 0, Symmetric.TagSize);

            // Getting the tag
            var hash = new Strobe("DiscoMAC", Symmetric.SecurityParameter);

            hash.Ad(false, key);
            hash.Ad(false, plainText);

            // verifying the tag
            if (!hash.RecvMac(false, tag))
            {
                throw new Exception("disco: the plaintext has been modified");
            }

            return(plainText);
        }
Esempio n. 16
0
 internal SymmetricState(string protocolName)
 {
     this.strobeState = new Strobe(protocolName, Symmetric.SecurityParameter);
 }
Esempio n. 17
0
        /// <summary>
        /// Read handshake message and output payload
        /// </summary>
        /// <param name="message">Noise message</param>
        /// <param name="payloadBuffer">payload buffer</param>
        /// <returns>Tuple of strobe state for initiator and responder</returns>
        public (Strobe initiatorState, Strobe responderState) ReadMessage(byte[] message, out byte[] payloadBuffer)
        {
            Strobe initiatorState = null;
            Strobe responderState = null;

            payloadBuffer = new byte[] { };

            // is it our turn to read?
            if (this.ShouldWrite)
            {
                throw new Exception("disco: unexpected call to ReadMessage should be WriteMessage");
            }

            // do we have a token to process?
            if (this.MessagePatterns.Length == 0 || this.MessagePatterns[0].Tokens.Count == 0)
            {
                throw new Exception("disco: no more tokens or message patterns to write");
            }

            // process the patterns
            var offset = 0;

            foreach (var pattern in this.MessagePatterns[0])
            {
                switch (pattern)
                {
                case Tokens.TokenE:
                {
                    if (message.Length - offset < Asymmetric.DhLen)
                    {
                        throw new Exception("disco: the received ephemeral key is to short");
                    }

                    this.Re = new KeyPair {
                        PublicKey = message.Skip(offset).Take(Asymmetric.DhLen).ToArray()
                    };
                    offset += Asymmetric.DhLen;
                    this.SymmetricState.MixHash(this.Re.PublicKey);
                    if (this.Psk?.Length > 0)
                    {
                        this.SymmetricState.MixKey(this.Re.PublicKey);
                    }

                    break;
                }

                case Tokens.TokenS:
                {
                    var tagLen = 0;
                    if (this.SymmetricState.IsKeyed)
                    {
                        tagLen = Symmetric.TagSize;
                    }

                    if (message.Length - offset < Asymmetric.DhLen + tagLen)
                    {
                        throw new Exception("disco: the received static key is to short");
                    }

                    var decrypted = this.SymmetricState.DecryptAndHash(
                        message.Skip(offset).Take(Asymmetric.DhLen + tagLen).ToArray());

                    // if we already know the remote static, compare
                    this.Rs = new KeyPair {
                        PublicKey = decrypted
                    };
                    offset += Asymmetric.DhLen + tagLen;
                    break;
                }

                case Tokens.TokenEE:
                {
                    this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Re.PublicKey));
                    break;
                }

                case Tokens.TokenES:
                {
                    if (this.Initiator)
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Rs.PublicKey));
                    }
                    else
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Re.PublicKey));
                    }

                    break;
                }

                case Tokens.TokenSE:
                {
                    if (this.Initiator)
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Re.PublicKey));
                    }
                    else
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Rs.PublicKey));
                    }

                    break;
                }

                case Tokens.TokenSS:
                {
                    this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Rs.PublicKey));
                    break;
                }

                case Tokens.TokenPsk:
                {
                    this.SymmetricState.MixKeyAndHash(this.Psk);
                    break;
                }
                }
            }

            // Appends decrpyAndHash(payload) to the buffer
            var plaintext = this.SymmetricState.DecryptAndHash(message.Skip(offset).ToArray());

            payloadBuffer = payloadBuffer.Concat(plaintext).ToArray();

            // remove the pattern from the messagePattern
            if (this.MessagePatterns.Length == 1)
            {
                this.MessagePatterns = null;
                // If there are no more message patterns returns two new CipherState object
                (initiatorState, responderState) = this.SymmetricState.Split();
            }
            else
            {
                this.MessagePatterns = this.MessagePatterns.Skip(1).ToArray();
            }

            // change the direction
            this.ShouldWrite = true;

            return(initiatorState, responderState);
        }
Esempio n. 18
0
        /// <summary>
        /// Perform handshake protocol if it has not been already run.
        /// </summary>
        /// <remarks>
        /// Most uses of this package need not call Handshake explicitly:
        /// the first Read or Write will call it automatically.
        /// </remarks>
        internal void HandShake()
        {
            // Locking the handshakeMutex
            this.handshakeMutex.WaitOne();

            HandshakeState handshakeState = null;

            try
            {
                Strobe c1;
                Strobe c2;
                byte[] receivedPayload = null;

                // did we already go through the handshake?
                if (this.handshakeComplite)
                {
                    return;
                }

                KeyPair remoteKeyPair = null;
                if (this.config.RemoteKey != null)
                {
                    if (this.config.RemoteKey.Length != Asymmetric.DhLen)
                    {
                        throw new Exception($"disco: the provided remote key is not {Asymmetric.DhLen}-byte");
                    }

                    remoteKeyPair = new KeyPair {
                        PublicKey = new byte[this.config.RemoteKey.Length]
                    };
                    Array.Copy(this.config.RemoteKey, remoteKeyPair.PublicKey, this.config.RemoteKey.Length);
                }

                handshakeState = DiscoHelper.InitializeDisco(
                    this.config.HandshakePattern,
                    this.isClient,
                    this.config.Prologue,
                    this.config.KeyPair,
                    null,
                    remoteKeyPair,
                    null);

                // pre-shared key
                handshakeState.Psk = this.config.PreSharedKey;

                do
                {
                    // start handshake
                    if (handshakeState.ShouldWrite)
                    {
                        // we're writing the next message pattern
                        // if it's the message pattern and we're sending a static key, we also send a proof
                        // TODO: is this the best way of sending a proof :/ ?
                        byte[] bufToWrite;

                        if (handshakeState.MessagePatterns.Length <= 2 && this.config.StaticPublicKeyProof != null)
                        {
                            (c1, c2) = handshakeState.WriteMessage(this.config.StaticPublicKeyProof, out bufToWrite);
                        }
                        else
                        {
                            (c1, c2) = handshakeState.WriteMessage(new byte[] { }, out bufToWrite);
                        }

                        // header (length)
                        var length = new[] { (byte)(bufToWrite.Length >> 8), (byte)(bufToWrite.Length % 256) };
                        // write
                        var dataToWrite = length.Concat(bufToWrite).ToArray();
                        this.connectionStream.Write(dataToWrite, 0, dataToWrite.Length);
                    }
                    else
                    {
                        var bufHeader = this.ReadFromUntil(this.connectionStream, 2);

                        var length = (bufHeader[0] << 8) | bufHeader[1];

                        if (length > Config.NoiseMessageLength)
                        {
                            throw new Exception("disco: Disco message received exceeds DiscoMessageLength");
                        }

                        var noiseMessage = this.ReadFromUntil(this.connectionStream, length);

                        (c1, c2) = handshakeState.ReadMessage(noiseMessage, out receivedPayload);
                    }
                }while (c1 == null);

                // Has the other peer been authenticated so far?
                if (!this.isRemoteAuthenticated && this.config.PublicKeyVerifier != null)
                {
                    byte isRemoteStaticKeySet = 0;
                    // test if remote static key is empty
                    foreach (var val in handshakeState.Rs.PublicKey)
                    {
                        isRemoteStaticKeySet |= val;
                    }

                    if (isRemoteStaticKeySet != 0)
                    {
                        // a remote static key has been received. Verify it
                        if (!this.config.PublicKeyVerifier(handshakeState.Rs.PublicKey, receivedPayload))
                        {
                            throw new Exception("disco: the received public key could not be authenticated");
                        }

                        this.isRemoteAuthenticated = true;
                        this.RemotePublicKey       = handshakeState.Rs.PublicKey;
                    }
                }

                // Processing the final handshake message returns two CipherState objects
                // the first for encrypting transport messages from initiator to responder
                // and the second for messages in the other direction.
                if (c2 != null)
                {
                    if (this.isClient)
                    {
                        (this.strobeOut, this.strobeIn) = (c1, c2);
                    }
                    else
                    {
                        (this.strobeOut, this.strobeIn) = (c2, c1);
                    }
                }
                else
                {
                    this.IsHalfDuplex = true;
                    this.strobeIn     = c1;
                    this.strobeOut    = c1;
                }

                // TODO: preserve c.hs.symmetricState.h
                // At that point the HandshakeState should be deleted except for the hash value h, which may be used for post-handshake channel binding (see Section 11.2).
                handshakeState.Dispose();

                // no errors :)
                this.handshakeComplite = true;
            }
            finally
            {
                handshakeState?.Dispose();
                this.handshakeMutex.ReleaseMutex();
            }
        }
Esempio n. 19
0
 public Transcript(byte[] label)
 {
     _obj = new Strobe(MERLIN_PROTOCOL_LABEL, 128);
     AppendMessage(Encoding.UTF8.GetBytes("dom-sep"), label);
 }
Esempio n. 20
0
 private Transcript(Strobe obj)
 {
     _obj = obj.Clone() as Strobe;
 }
Esempio n. 21
0
        /// <summary>
        /// Write payload with handshake message using current state
        /// </summary>
        /// <param name="payload">payload to write</param>
        /// <param name="messageBuffer">output message buffer</param>
        /// <returns>Tuple of strobe state for initiator and responder</returns>
        internal (Strobe initiatorState, Strobe responderState) WriteMessage(byte[] payload, out byte[] messageBuffer)
        {
            Strobe initiatorState = null;
            Strobe responderState = null;

            messageBuffer = new byte[] { };

            // is it our turn to write?
            if (!this.ShouldWrite)
            {
                throw new Exception("disco: unexpected call to WriteMessage should be ReadMessage");
            }

            // do we have a token to process?
            if (this.MessagePatterns.Length == 0 || this.MessagePatterns[0].Tokens.Count == 0)
            {
                throw new Exception("disco: no more tokens or message patterns to write");
            }

            // process the patterns
            foreach (var pattern in this.MessagePatterns[0])
            {
                switch (pattern)
                {
                case Tokens.TokenE:
                {
                    // debug
                    if (this.DebugEphemeral != null)
                    {
                        this.E = this.DebugEphemeral;
                    }
                    else
                    {
                        this.E = Asymmetric.GenerateKeyPair();
                    }

                    messageBuffer = messageBuffer.Concat(this.E.PublicKey).ToArray();
                    this.SymmetricState.MixHash(this.E.PublicKey);
                    if (this.Psk?.Length > 0)
                    {
                        this.SymmetricState.MixKey(this.E.PublicKey);
                    }

                    break;
                }

                case Tokens.TokenS:
                {
                    var encrypted = this.SymmetricState.EncryptAndHash(this.S.PublicKey);
                    messageBuffer = messageBuffer.Concat(encrypted).ToArray();
                    break;
                }

                case Tokens.TokenEE:
                {
                    this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Re.PublicKey));
                    break;
                }

                case Tokens.TokenES:
                {
                    if (this.Initiator)
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Rs.PublicKey));
                    }
                    else
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Re.PublicKey));
                    }

                    break;
                }

                case Tokens.TokenSE:
                {
                    if (this.Initiator)
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Re.PublicKey));
                    }
                    else
                    {
                        this.SymmetricState.MixKey(Asymmetric.Dh(this.E, this.Rs.PublicKey));
                    }

                    break;
                }

                case Tokens.TokenSS:
                {
                    this.SymmetricState.MixKey(Asymmetric.Dh(this.S, this.Rs.PublicKey));
                    break;
                }

                case Tokens.TokenPsk:
                {
                    this.SymmetricState.MixHash(this.Psk);
                    break;
                }

                default:
                {
                    throw new Exception("Disco: token not recognized");
                }
                }
            }

            // Appends EncryptAndHash(payload) to the buffer
            var ciphertext = this.SymmetricState.EncryptAndHash(payload);

            messageBuffer = messageBuffer.Concat(ciphertext).ToArray();

            // are there more message patterns to process?
            if (this.MessagePatterns.Length == 1)
            {
                this.MessagePatterns = null;
                // If there are no more message patterns returns two new CipherState objects
                (initiatorState, responderState) = this.SymmetricState.Split();
            }
            else
            {
                // remove the pattern from the messagePattern
                this.MessagePatterns = this.MessagePatterns.Skip(1).ToArray();
            }

            // change the direction
            this.ShouldWrite = false;

            return(initiatorState, responderState);
        }