Example #1
0
        PullMsgResult ProduceInitiate(ref Msg msg)
        {
            int metadataLength = BasicPropertiesLength;

            byte[] metadataPlaintext = new byte[metadataLength];
            AddBasicProperties(metadataPlaintext);
            msg.InitPool(113 + 128 + metadataLength + Curve25519XSalsa20Poly1305.TagLength);

            Span <byte> vouchNonce     = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength];
            Span <byte> vouchPlaintext = stackalloc byte[64];
            Span <byte> vouchBox       = stackalloc byte[Curve25519XSalsa20Poly1305.TagLength + 64];

            //  Create vouch = Box [C',S](C->S')
            m_cnPublicKey.CopyTo(vouchPlaintext);
            m_serverKey.CopyTo(vouchPlaintext.Slice(32));

            VouchNoncePrefix.CopyTo(vouchNonce);
            using var rng = RandomNumberGenerator.Create();
#if NETSTANDARD2_1
            rng.GetBytes(vouchNonce.Slice(8));
#else
            byte[] temp = new byte[16];
            rng.GetBytes(temp);
            temp.CopyTo(vouchNonce.Slice(8));
#endif

            using var box = new Curve25519XSalsa20Poly1305(m_secretKey, m_cnServerKey);
            box.Encrypt(vouchBox, vouchPlaintext, vouchNonce);

            Span <byte> initiate          = msg;
            Span <byte> initiateNonce     = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength];
            Span <byte> initiatePlaintext = new byte[128 + metadataLength];
            Span <byte> initiateBox       = initiate.Slice(113);

            //  Create Box [C + vouch + metadata](C'->S')
            m_publicKey.CopyTo(initiatePlaintext);
            vouchNonce.Slice(8).CopyTo(initiatePlaintext.Slice(32));
            vouchBox.CopyTo(initiatePlaintext.Slice(48));
            metadataPlaintext.CopyTo(initiatePlaintext.Slice(48 + 80));
            Array.Clear(metadataPlaintext, 0, metadataPlaintext.Length);

            InitiatieNoncePrefix.CopyTo(initiateNonce);
            NetworkOrderBitsConverter.PutUInt64(m_nonce, initiateNonce.Slice(16));

            using var box2 = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_cnServerKey);
            box2.Encrypt(initiateBox, initiatePlaintext, initiateNonce);

            InitiateLiteral.CopyTo(initiate);

            //  Cookie provided by the server in the WELCOME command
            m_cnCookie.CopyTo(initiate.Slice(9, 96));

            //  Short nonce, prefixed by "CurveZMQINITIATE"
            initiateNonce.Slice(16).CopyTo(initiate.Slice(105));

            m_nonce++;

            return(PullMsgResult.Ok);
        }
Example #2
0
        PushMsgResult ProcessInitiate(ref Msg msg)
        {
            if (!CheckBasicCommandStructure(ref msg))
            {
                return(PushMsgResult.Error);
            }

            Span <byte> initiate = msg;

            if (!IsCommand("INITIATE", ref msg))
            {
                return(PushMsgResult.Error);
            }

            if (initiate.Length < 257)
            {
                return(PushMsgResult.Error);
            }

            Span <byte> cookieNonce     = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength];
            Span <byte> cookiePlaintext = stackalloc byte[64];
            Span <byte> cookieBox       = initiate.Slice(25, 80);

            CookieNoncePrefix.CopyTo(cookieNonce);
            initiate.Slice(9, 16).CopyTo(cookieNonce.Slice(8));

            using var secretBox = new XSalsa20Poly1305(m_cookieKey);
            bool decrypted = secretBox.TryDecrypt(cookiePlaintext, cookieBox, cookieNonce);

            if (!decrypted)
            {
                return(PushMsgResult.Error);
            }

            //  Check cookie plain text is as expected [C' + s']
            if (!SpanUtility.Equals(m_cnClientKey, cookiePlaintext.Slice(0, 32)) ||
                !SpanUtility.Equals(m_cnSecretKey, cookiePlaintext.Slice(32, 32)))
            {
                return(PushMsgResult.Error);
            }

            Span <byte> initiateNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength];

            byte[] initiatePlaintext = new byte[msg.Size - 113];
            var    initiateBox       = initiate.Slice(113);

            InitiatieNoncePrefix.CopyTo(initiateNonce);
            initiate.Slice(105, 8).CopyTo(initiateNonce.Slice(16));
            m_peerNonce = NetworkOrderBitsConverter.ToUInt64(initiate, 105);

            using var box = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_cnClientKey);
            bool decrypt = box.TryDecrypt(initiatePlaintext, initiateBox, initiateNonce);

            if (!decrypt)
            {
                return(PushMsgResult.Error);
            }

            Span <byte> vouchNonce     = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength];
            Span <byte> vouchPlaintext = stackalloc byte[64];
            Span <byte> vouchBox       = new Span <byte>(initiatePlaintext, 48, 80);
            var         clientKey      = new Span <byte>(initiatePlaintext, 0, 32);

            VouchNoncePrefix.CopyTo(vouchNonce);
            new Span <byte>(initiatePlaintext, 32, 16).CopyTo(vouchNonce.Slice(8));

            using var box2 = new Curve25519XSalsa20Poly1305(m_cnSecretKey, clientKey);
            decrypt        = box2.TryDecrypt(vouchPlaintext, vouchBox, vouchNonce);
            if (!decrypt)
            {
                return(PushMsgResult.Error);
            }

            //  What we decrypted must be the client's short-term public key
            if (!SpanUtility.Equals(vouchPlaintext.Slice(0, 32), m_cnClientKey))
            {
                return(PushMsgResult.Error);
            }

            //  Create the session box
            m_box = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_cnClientKey);

            //  This supports the Stonehouse pattern (encryption without authentication).
            m_state = State.SendingReady;

            if (!ParseMetadata(new Span <byte>(initiatePlaintext, 128, initiatePlaintext.Length - 128 - 16)))
            {
                return(PushMsgResult.Error);
            }

            vouchPlaintext.Clear();
            Array.Clear(initiatePlaintext, 0, initiatePlaintext.Length);

            return(PushMsgResult.Ok);
        }