PullMsgResult ProduceWelcome(ref Msg msg) { Span <byte> cookieNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; Span <byte> cookiePlaintext = stackalloc byte[64]; Span <byte> cookieCiphertext = stackalloc byte[64 + XSalsa20Poly1305.TagLength]; // Create full nonce for encryption // 8-byte prefix plus 16-byte random nonce CookieNoncePrefix.CopyTo(cookieNonce); using var rng = RandomNumberGenerator.Create(); #if NETSTANDARD2_1 rng.GetBytes(cookieNonce.Slice(8)); #else byte[] temp = new byte[16]; rng.GetBytes(temp); temp.CopyTo(cookieNonce.Slice(8)); #endif // Generate cookie = Box [C' + s'](t) m_cnClientKey.CopyTo(cookiePlaintext); m_cnSecretKey.CopyTo(cookiePlaintext.Slice(32)); // Generate fresh cookie key rng.GetBytes(m_cookieKey); // Encrypt using symmetric cookie key using var secretBox = new XSalsa20Poly1305(m_cookieKey); secretBox.Encrypt(cookieCiphertext, cookiePlaintext, cookieNonce); cookiePlaintext.Clear(); Span <byte> welcomeNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; Span <byte> welcomePlaintext = stackalloc byte[128]; Span <byte> welcomeCiphertext = stackalloc byte[128 + Curve25519XSalsa20Poly1305.TagLength]; // Create full nonce for encryption // 8-byte prefix plus 16-byte random nonce WelcomeNoncePrefix.CopyTo(welcomeNonce); #if NETSTANDARD2_1 rng.GetBytes(welcomeNonce.Slice(8)); #else rng.GetBytes(temp); temp.CopyTo(welcomeNonce.Slice(8)); #endif // Create 144-byte Box [S' + cookie](S->C') m_cnPublicKey.CopyTo(welcomePlaintext); cookieNonce.Slice(8).CopyTo(welcomePlaintext.Slice(32)); cookieCiphertext.CopyTo(welcomePlaintext.Slice(48)); using var box = new Curve25519XSalsa20Poly1305(m_secretKey, m_cnClientKey); box.Encrypt(welcomeCiphertext, welcomePlaintext, welcomeNonce); welcomePlaintext.Clear(); msg.InitPool(168); // TODO: we can save some allocation here by allocating this earlier Span <byte> welcome = msg; WelcomeLiteral.CopyTo(welcome); welcomeNonce.Slice(8, 16).CopyTo(welcome.Slice(8)); welcomeCiphertext.CopyTo(welcome.Slice(24)); return(PullMsgResult.Ok); }
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); }
PullMsgResult ProduceHello(ref Msg msg) { msg.InitPool(200); Span <byte> helloNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; Span <byte> helloPlaintext = stackalloc byte[64]; Span <byte> helloBox = msg.Slice(120); // Prepare the full nonce HelloNoncePrefix.CopyTo(helloNonce); NetworkOrderBitsConverter.PutUInt64(m_nonce, helloNonce.Slice(16)); // Create Box [64 * %x0](C'->S) using var box = new Curve25519XSalsa20Poly1305(m_cnSecretKey, m_serverKey); box.Encrypt(helloBox, helloPlaintext, helloNonce); Span <byte> hello = msg; HelloLiteral.CopyTo(hello); // CurveZMQ major and minor version numbers hello[6] = 1; hello[7] = 0; // 8-80 are left zeros for anti-amplification padding // Client public connection key m_cnPublicKey.CopyTo(hello.Slice(80)); // Short nonce, prefixed by "CurveZMQHELLO---" helloNonce.Slice(16).CopyTo(hello.Slice(112)); m_nonce++; return(PullMsgResult.Ok); }
public override PullMsgResult Encode(ref Msg msg) { Span <byte> messageNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; m_encodeNoncePrefix.CopyTo(messageNonce); NetworkOrderBitsConverter.PutUInt64(m_nonce, messageNonce.Slice(16)); byte flags = 0; if (msg.HasMore) { flags |= 0x01; } if (msg.HasCommand) { flags |= 0x02; } Msg plaintext = new Msg(); plaintext.InitPool(msg.Size + 1); plaintext[0] = flags; msg.CopyTo(plaintext.Slice(1)); msg.Close(); msg.InitPool(16 + Curve25519XSalsa20Poly1305.TagLength + plaintext.Size); m_box.Encrypt(msg.Slice(16), plaintext, messageNonce); plaintext.Close(); MessageLiteral.CopyTo(msg); NetworkOrderBitsConverter.PutUInt64(m_nonce, msg.Slice(8)); m_nonce++; return(PullMsgResult.Ok); }