PushMsgResult ProcessReady(ref Msg msg) { if (msg.Size < 30) { return(PushMsgResult.Error); } Span <byte> readyNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; var readyPlaintext = new byte[msg.Size - 14 - Curve25519XSalsa20Poly1305.TagLength]; Span <byte> readyBox = msg.Slice(14); ReadyNoncePrefix.CopyTo(readyNonce); msg.Slice(6, 8).CopyTo(readyNonce.Slice(16)); m_peerNonce = NetworkOrderBitsConverter.ToUInt64(msg, 6); bool isDecrypted = m_box.TryDecrypt(readyPlaintext, readyBox, readyNonce); if (!isDecrypted) { return(PushMsgResult.Error); } if (!ParseMetadata(readyPlaintext)) { return(PushMsgResult.Error); } Array.Clear(readyPlaintext, 0, readyPlaintext.Length); m_state = State.Connected; return(PushMsgResult.Ok); }
PullMsgResult ProduceReady(ref Msg msg) { int metadataLength = BasicPropertiesLength; Span <byte> readyNonce = stackalloc byte[Curve25519XSalsa20Poly1305.NonceLength]; byte[] readyPlaintext = new byte[metadataLength]; // Create Box [metadata](S'->C') AddBasicProperties(readyPlaintext); ReadyNoncePrefix.CopyTo(readyNonce); NetworkOrderBitsConverter.PutUInt64(m_nonce, readyNonce.Slice(16)); msg.InitPool(14 + Curve25519XSalsa20Poly1305.TagLength + metadataLength); var readyBox = msg.Slice(14); m_box.Encrypt(readyBox, readyPlaintext, readyNonce); Array.Clear(readyPlaintext, 0, readyPlaintext.Length); Span <byte> ready = msg; ReadyLiteral.CopyTo(ready); // Short nonce, prefixed by "CurveZMQREADY---" readyNonce.Slice(16).CopyTo(ready.Slice(6)); m_nonce++; return(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); }
/// <summary> /// Parses a metadata. /// Metadata consists of a list of properties consisting of /// name and value as size-specified strings. /// </summary> /// <returns>Returns true on success and false on error.</returns> protected bool ParseMetadata(Span <byte> source) { while (source.Length > 1) { int nameLength = source[0]; source = source.Slice(NameLengthSize); if (source.Length < nameLength) { break; } string name = SpanUtility.ToAscii(source.Slice(0, nameLength)); source = source.Slice(nameLength); if (source.Length < ValueLengthSize) { break; } int valueLength = NetworkOrderBitsConverter.ToInt32(source); source = source.Slice(ValueLengthSize); if (source.Length < valueLength) { break; } byte[] value = new byte[valueLength]; source.Slice(0, valueLength).CopyTo(value); source = source.Slice(valueLength); if (name == ZmtpPropertyIdentity && Options.RecvIdentity) { PeerIdentity = value; } else if (name == ZmtpPropertySocketType) { if (!CheckSocketType(Encoding.ASCII.GetString(value))) { return(false); } } else { if (!GetProperty(name, value, valueLength)) { return(false); } } } if (source.Length > 0) { return(false); } return(true); }
/// <inheritdoc/> public override DateTimeOffset?GetBlockPerceivedTime(HashDigest <SHA256> blockHash) { byte[] key = BlockKey(blockHash); if (_blockPerceptionDb.Get(key) is { } bytes) { long unixTimeMs = NetworkOrderBitsConverter.ToInt64(bytes); return(DateTimeOffset.FromUnixTimeMilliseconds(unixTimeMs)); } return(null); }
/// <inheritdoc/> public override void SetBlockPerceivedTime( HashDigest <SHA256> blockHash, DateTimeOffset perceivedTime ) { byte[] key = BlockKey(blockHash); _blockPerceptionDb.Put( key, NetworkOrderBitsConverter.GetBytes(perceivedTime.ToUnixTimeMilliseconds()) ); }
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); }
private static byte[] GetMessage(int version, IValue extra) { byte[] msg = NetworkOrderBitsConverter.GetBytes(version); if (!(extra is null)) { byte[] extraBytes = _codec.Encode(extra); int versionLength = msg.Length; Array.Resize(ref msg, versionLength + extraBytes.Length); extraBytes.CopyTo(msg, versionLength); } return(msg); }
private static void RoundTripInt32(int num, params byte[] bytes) { byte[] buffer = NetworkOrderBitsConverter.GetBytes(num); Assert.AreEqual(4, buffer.Length); CollectionAssert.AreEqual(bytes, buffer); Assert.AreEqual(num, NetworkOrderBitsConverter.ToInt32(buffer)); NetworkOrderBitsConverter.PutInt32(num, buffer); CollectionAssert.AreEqual(bytes, buffer); Assert.AreEqual(num, NetworkOrderBitsConverter.ToInt32(buffer)); }
private static void RoundTripInt16(short num, params byte[] bytes) { byte[] buffer = NetworkOrderBitsConverter.GetBytes(num); Assert.Equal(2, buffer.Length); Assert.Equal(bytes, buffer); Assert.Equal(num, NetworkOrderBitsConverter.ToInt16(buffer)); NetworkOrderBitsConverter.PutInt16(num, buffer); Assert.Equal(bytes, buffer); Assert.Equal(num, NetworkOrderBitsConverter.ToInt16(buffer)); }
public void TrySignalTest() { var socket = new MockOutgoingSocket((ref Msg msg, TimeSpan timeout, bool more) => { Assert.Equal(TimeSpan.Zero, timeout); Assert.Equal(8, msg.Data.Length); var value = NetworkOrderBitsConverter.ToInt64(msg.Data); Assert.Equal(0x7766554433221100L, value); Assert.False(more); return(true); }); Assert.True(socket.TrySignalOK()); }
public void SignalTest() { OutgoingSocketMock socket = new OutgoingSocketMock((ref Msg msg, TimeSpan timeout, bool more) => { Assert.AreEqual(SendReceiveConstants.InfiniteTimeout, timeout); Assert.AreEqual(8, msg.Data.Length); long value = NetworkOrderBitsConverter.ToInt64(msg.Data); Assert.AreEqual(0x7766554433221100L, value); Assert.IsFalse(more); return(true); }); socket.SignalOK(); }
public void TrySignalFailedTest() { OutgoingSocketMock socket = new OutgoingSocketMock((ref Msg msg, TimeSpan timeout, bool more) => { Assert.AreEqual(TimeSpan.Zero, timeout); Assert.AreEqual(8, msg.Data.Length); long value = NetworkOrderBitsConverter.ToInt64(msg.Data); Assert.AreEqual(0x7766554433221100L, value); Assert.IsFalse(more); return(false); }); Assert.IsFalse(socket.TrySignalOK()); }
/// <inheritdoc cref="BaseStore.SetBlockPerceivedTime(BlockHash, DateTimeOffset)"/> public override void SetBlockPerceivedTime( BlockHash blockHash, DateTimeOffset perceivedTime ) { try { byte[] key = BlockKey(blockHash); _blockPerceptionDb.Put( key, NetworkOrderBitsConverter.GetBytes(perceivedTime.ToUnixTimeMilliseconds()) ); } catch (Exception e) { LogUnexpectedException(nameof(SetBlockPerceivedTime), e); } }
/// <inheritdoc cref="BaseStore.GetBlockPerceivedTime(BlockHash)"/> public override DateTimeOffset?GetBlockPerceivedTime(BlockHash blockHash) { try { byte[] key = BlockKey(blockHash); if (_blockPerceptionDb.Get(key) is { } bytes) { long unixTimeMs = NetworkOrderBitsConverter.ToInt64(bytes); return(DateTimeOffset.FromUnixTimeMilliseconds(unixTimeMs)); } } catch (Exception e) { LogUnexpectedException(nameof(GetBlockPerceivedTime), e); } return(null); }
public void TestInt64() { byte[] buffer = NetworkOrderBitsConverter.GetBytes(1); Assert.AreEqual(1, buffer[3]); Assert.AreEqual(0, buffer[0]); long num = NetworkOrderBitsConverter.ToInt32(buffer); Assert.AreEqual(1, num); NetworkOrderBitsConverter.PutInt32(16777216, buffer, 0); Assert.AreEqual(1, buffer[0]); Assert.AreEqual(0, buffer[3]); num = NetworkOrderBitsConverter.ToInt32(buffer); Assert.AreEqual(16777216, num); }
public void TestInt32() { byte[] buffer = NetworkOrderBitsConverter.GetBytes((long)1); Assert.AreEqual(buffer[7], 1); Assert.AreEqual(0, buffer[0]); long num = NetworkOrderBitsConverter.ToInt64(buffer); Assert.AreEqual(1, num); NetworkOrderBitsConverter.PutInt64(72057594037927936, buffer, 0); Assert.AreEqual(1, buffer[0]); Assert.AreEqual(0, buffer[7]); num = NetworkOrderBitsConverter.ToInt64(buffer); Assert.AreEqual(72057594037927936, num); }
public void Constructor() { // Generate fixture block hashes looks like 0x000...1, 0x000...2, 0x000...3, and so on, // for the sake of easier debugging. ImmutableArray <HashDigest <SHA256> > blocks = Enumerable.Range(0, 0x10).Select(i => { byte[] bytes = NetworkOrderBitsConverter.GetBytes(i); var buffer = new byte[HashDigest <SHA256> .Size]; bytes.CopyTo(buffer, buffer.Length - bytes.Length); return(new HashDigest <SHA256>(buffer)); }).ToImmutableArray(); var locator = new BlockLocator( indexBlockHash: idx => blocks[(int)(idx < 0 ? blocks.Length + idx : idx)], indexByBlockHash: hash => blocks.IndexOf(hash), sampleAfter: 5 ); foreach (HashDigest <SHA256> hash in locator) { _output.WriteLine(hash.ToString()); } Assert.Equal( new[] { blocks[0xf], blocks[0xe], blocks[0xd], blocks[0xc], blocks[0xb], blocks[0xa], blocks[0x8], blocks[0x4], blocks[0x0], }, locator ); }
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); Assumes.NotNull(m_box); 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); }
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); }
protected int AddProperty(byte[] output, int outputOffset, string name, byte[] value) { if (name.Length > 255) { throw new ArgumentException("property name length exceed maximum size"); } int totalLength = GetPropertyLength(name, value.Length); if (totalLength > (output.Length - outputOffset)) { throw new Exception("totalLength of property exceed maximum size"); } output[outputOffset] = (byte)name.Length; outputOffset += NameLengthSize; System.Text.Encoding.ASCII.GetBytes(name, 0, name.Length, output, outputOffset); outputOffset += name.Length; NetworkOrderBitsConverter.PutInt32(value.Length, output, outputOffset); outputOffset += ValueLengthSize; Buffer.BlockCopy(value, 0, output, outputOffset, value.Length); return(totalLength); }
protected int AddProperty(Span <byte> output, string name, byte[] value) { if (name.Length > 255) { throw new ArgumentException("property name length exceed maximum size"); } int totalLength = GetPropertyLength(name, value.Length); if (totalLength > output.Length) { throw new Exception("totalLength of property exceed maximum size"); } output[0] = (byte)name.Length; output = output.Slice(NameLengthSize); System.Text.Encoding.ASCII.GetBytes(name, output); output = output.Slice(name.Length); NetworkOrderBitsConverter.PutInt32(value.Length, output); output = output.Slice(ValueLengthSize); value.CopyTo(output); return(totalLength); }
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); }
/// <summary> /// Parses a metadata. /// Metadata consists of a list of properties consisting of /// name and value as size-specified strings. /// </summary> /// <returns>Returns true on success and false on error.</returns> protected bool ParseMetadata(byte[] source, int offset, int length) { int bytesLeft = length; while (bytesLeft > 1) { int nameLength = source[offset]; offset += NameLengthSize; bytesLeft -= NameLengthSize; if (bytesLeft < nameLength) { break; } string name = Encoding.ASCII.GetString(source, offset, nameLength); offset += nameLength; bytesLeft -= nameLength; if (bytesLeft < ValueLengthSize) { break; } int valueLength = NetworkOrderBitsConverter.ToInt32(source, offset); offset += ValueLengthSize; bytesLeft -= ValueLengthSize; if (bytesLeft < valueLength) { break; } byte[] value = new byte[valueLength]; Buffer.BlockCopy(source, offset, value, 0, valueLength); offset += valueLength; bytesLeft -= valueLength; if (name == ZmtpPropertyIdentity && Options.RecvIdentity) { PeerIdentity = value; } else if (name == ZmtpPropertySocketType) { if (!CheckSocketType(Encoding.ASCII.GetString(value))) { return(false); } } else { if (!GetProperty(name, value, valueLength)) { return(false); } } } if (bytesLeft > 0) { return(false); } return(true); }
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); Assumes.NotNull(m_box); 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); }