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); }
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); }