public byte[] Serialize <T>(CryptoDtoChannel channel, CryptoDtoMode mode, T obj) { ArrayBufferWriter <byte> arrayBufferWriter = new ArrayBufferWriter <byte>(); Serialize(arrayBufferWriter, channel, mode, obj); return(arrayBufferWriter.WrittenSpan.ToArray()); }
internal Deserializer(CryptoDtoChannel channel, ushort headerLength, CryptoDtoHeaderDto header, ReadOnlySpan <byte> bytes, bool ignoreSequence, IBufferWriter <byte> plaintextBuffer) { sequenceValid = false; channelTag = header.ChannelTag; switch (header.Mode) { case CryptoDtoMode.ChaCha20Poly1305: { int adLength = 2 + headerLength; int aeLength = bytes.Length - adLength - 16; ReadOnlySpan <byte> ad = bytes.Slice(0, adLength); ReadOnlySpan <byte> ae = bytes.Slice(adLength, aeLength); ReadOnlySpan <byte> tag = bytes.Slice(adLength + aeLength, 16); Span <byte> nonce = stackalloc byte[Aead.NonceSize]; BinaryPrimitives.WriteUInt64LittleEndian(nonce.Slice(4), header.Sequence); var aead = channel.ReceiveChaCha20Poly1305; Memory <byte> plaintext = plaintextBuffer.GetMemory(aeLength).Slice(0, aeLength); aead.Decrypt(nonce, ae, tag, plaintext.Span, ad); if (ignoreSequence) { sequenceValid = channel.IsReceivedSequenceAllowed(header.Sequence); } else { channel.CheckReceivedSequence(header.Sequence); //The packet has passed MAC, so now check if it's being duplicated or replayed sequenceValid = true; } var dtoNameLength = Unsafe.ReadUnaligned <ushort>(ref MemoryMarshal.GetReference(plaintext.Span)); //.NET Standard 2.0 doesn't have BitConverter.ToUInt16(Span<T>) if (plaintext.Length < (2 + dtoNameLength)) { throw new CryptographicException("Not enough bytes to process packet. (2) " + dtoNameLength + " " + plaintext.Length); } dtoNameBuffer = plaintext.Span.Slice(2, dtoNameLength); var dtoLength = Unsafe.ReadUnaligned <ushort>(ref MemoryMarshal.GetReference(plaintext.Span.Slice(2 + dtoNameLength, 2))); //.NET Standard 2.0 doesn't have BitConverter.ToUInt16(Span<T>) if (plaintext.Length < (2 + dtoNameLength + 2 + dtoLength)) { throw new CryptographicException("Not enough bytes to process packet. (3) " + dtoLength + " " + plaintext.Length); } dtoBuffer = plaintext.Slice(2 + dtoNameLength + 2, dtoLength); break; } default: throw new CryptographicException("Mode not recognised"); } }
public static Deserializer Deserialize(IBufferWriter <byte> plaintextBuffer, CryptoDtoChannel channel, ReadOnlyMemory <byte> bytes) { var header = Deserializer.GetHeader(bytes, out ushort headerLength); if (header.ChannelTag != channel.ChannelTag) { throw new CryptographicException("Channel Tag doesn't match provided Channel"); } return(new Deserializer(channel, headerLength, header, bytes.Span, false, plaintextBuffer)); }
// Hint for callers using ArrayBufferWriter<byte> - output.WrittenSpan contains the serialised data public void Serialize <T>(IBufferWriter <byte> output, CryptoDtoChannel channel, CryptoDtoMode mode, T dto) { lock (bufferLock) { ReadOnlySpan <byte> dtoNameBuffer = GetDtoNameBytes <T>(); dtoBuffer.Clear(); MessagePackSerializer.Serialize(dtoBuffer, dto); Pack(output, channel, mode, dtoNameBuffer, dtoBuffer.WrittenSpan); } }
public void CreateChannel(string channelTag, int receiveSequenceHistorySize = 10) { lock (channelStoreLock) { if (channelStore.ContainsKey(channelTag)) { throw new CryptographicException("Key tag already exists in store. (" + channelTag + ")"); } channelStore[channelTag] = new CryptoDtoChannel(channelTag, receiveSequenceHistorySize); } }
public bool TryCreateChannel(string channelTag, int receiveSequenceHistorySize = 10) { lock (channelStoreLock) { if (channelStore.ContainsKey(channelTag)) { return(false); } channelStore[channelTag] = new CryptoDtoChannel(channelTag, receiveSequenceHistorySize); return(true); } }
public void Pack(IBufferWriter <byte> output, CryptoDtoChannel channel, CryptoDtoMode mode, ReadOnlySpan <byte> dtoNameBuffer, ReadOnlySpan <byte> dtoBuffer) { channel.GetTransmitKey(mode, out ulong sequenceToSend); CryptoDtoHeaderDto header = new CryptoDtoHeaderDto { ChannelTag = channel.ChannelTag, Mode = mode, Sequence = sequenceToSend }; Pack(output, header, channel.TransmitChaCha20Poly1305, dtoNameBuffer, dtoBuffer); }
public bool TryGetChannel(string channelTag, out CryptoDtoChannel channel) { lock (channelStoreLock) { if (!channelStore.ContainsKey(channelTag)) { channel = null; return(false); } channel = channelStore[channelTag]; return(true); } }
public static Deserializer DeserializeIgnoreSequence(IBufferWriter <byte> plaintextBuffer, CryptoDtoChannel channel, ReadOnlyMemory <byte> bytes) //This is used for UDP channels where duplication is possible and the overhead of CryptographicException isn't acceptable. Use IsSequenceValid() in code to ignore the UDP packet. { var header = Deserializer.GetHeader(bytes, out ushort headerLength); if (header.ChannelTag != channel.ChannelTag) { throw new CryptographicException("Channel Tag doesn't match provided Channel"); } return(new Deserializer(channel, headerLength, header, bytes.Span, true, plaintextBuffer)); }
public static Deserializer DeserializeIgnoreSequence(CryptoDtoChannel channel, ReadOnlyMemory <byte> bytes) //This is used for UDP channels where duplication is possible and the overhead of CryptographicException isn't acceptable. Use IsSequenceValid() in code to ignore the UDP packet. { var plaintextBuffer = new ArrayBufferWriter <byte>(); return(DeserializeIgnoreSequence(plaintextBuffer, channel, bytes)); }
public static Deserializer Deserialize(CryptoDtoChannel channel, ReadOnlyMemory <byte> bytes) { var plaintextBuffer = new ArrayBufferWriter <byte>(); return(Deserialize(plaintextBuffer, channel, bytes)); }