PushMsgResult ProcessWelcome(ref Msg msg) { if (msg.Size != 168) { return(PushMsgResult.Error); } Span <byte> welcomeNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; Span <byte> welcomePlaintext = stackalloc byte[128]; Span <byte> welcomeBox = msg.Slice(24, 144); WelcomeNoncePrefix.CopyTo(welcomeNonce); msg.Slice(8, 16).CopyTo(welcomeNonce.Slice(8)); using var box = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_serverKey); bool isDecrypted = box.TryDecrypt(welcomePlaintext, welcomeBox, welcomeNonce); if (!isDecrypted) { return(PushMsgResult.Error); } m_cnServerKey = welcomePlaintext.Slice(0, 32).ToArray(); m_cnCookie = welcomePlaintext.Slice(32, 16 + 80).ToArray(); // Create the curve box m_box = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_cnServerKey); m_state = State.SendInitiate; return(PushMsgResult.Ok); }
public bool DecodeEndVerify(EncryptedVote vote, out byte[] decoded) { Curve25519XSalsa20Poly1305 box = new Curve25519XSalsa20Poly1305(_privateKey, vote.PublicKey.ParseHexEncodedValue()); var encryptedMessage = vote.Message.ParseHexEncodedValue(); var decryptedMessage = new byte[encryptedMessage.Length - XSalsa20Poly1305.TagLength]; var ret = box.TryDecrypt(decryptedMessage, encryptedMessage, vote.Nonce.ParseHexEncodedValue()); decoded = decryptedMessage; return(ret); }
PushMsgResult ProcessHello(ref Msg msg) { if (!CheckBasicCommandStructure(ref msg)) { return(PushMsgResult.Error); } Span <byte> hello = msg; if (!IsCommand("HELLO", ref msg)) { return(PushMsgResult.Error); } if (hello.Length != 200) { return(PushMsgResult.Error); } byte major = hello[6]; byte minor = hello[7]; if (major != 1 || minor != 0) { // client HELLO has unknown version number return(PushMsgResult.Error); } // Save client's short-term public key (C') hello.Slice(80, 32).CopyTo(m_cnClientKey); Span <byte> helloNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; HelloNoncePrefix.CopyTo(helloNonce); hello.Slice(112, 8).CopyTo(helloNonce.Slice(16)); m_peerNonce = NetworkOrderBitsConverter.ToUInt64(hello, 112); using var box = new Curve25519XSalsa20Poly1305(m_secretKey, m_cnClientKey); Span <byte> helloPlaintext = stackalloc byte[80]; bool isDecrypted = box.TryDecrypt(helloPlaintext, hello.Slice(120, 80), helloNonce); if (!isDecrypted) { return(PushMsgResult.Error); } helloPlaintext.Clear(); m_state = State.SendingWelcome; return(PushMsgResult.Ok); }
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); }
public override PushMsgResult Decode(ref Msg msg) { if (!CheckBasicCommandStructure(ref msg)) { return(PushMsgResult.Error); } int size = msg.Size; if (!IsCommand("MESSAGE", ref msg)) { return(PushMsgResult.Error); } if (size < 33) // Size of 16 bytes of command + 16 bytes of MAC + 1 byte for flag { return(PushMsgResult.Error); } Span <byte> messageNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; m_decodeNoncePrefix.CopyTo(messageNonce); msg.Slice(8, 8).CopyTo(messageNonce.Slice(16)); UInt64 nonce = NetworkOrderBitsConverter.ToUInt64(msg, 8); if (nonce <= m_peerNonce) { return(PushMsgResult.Error); } m_peerNonce = nonce; Msg plain = new Msg(); plain.InitPool(msg.Size - 16 - Curve25519XSalsa20Poly1305.TagLength); var isAuthenticate = m_box.TryDecrypt(plain, msg.Slice(16), messageNonce); if (!isAuthenticate) { plain.Close(); return(PushMsgResult.Error); } msg.Move(ref plain); byte flags = msg[0]; if ((flags & 0x01) != 0) { msg.SetFlags(MsgFlags.More); } if ((flags & 0x02) != 0) { msg.SetFlags(MsgFlags.Command); } msg.TrimPrefix(1); return(PushMsgResult.Ok); }