Esempio n. 1
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. 2
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);
        }