//Can we change the ChaCha20Poly1305 input to some kind of ICrypto interface or action with 'Encrypt' and 'Decrypt'? private void Pack(IBufferWriter <byte> output, CryptoDtoHeaderDto header, ChaCha20Poly1305 crypto, ReadOnlySpan <byte> dtoNameBuffer, ReadOnlySpan <byte> dtoBuffer) { lock (bufferLock) { headerBuffer.Clear(); MessagePackSerializer.Serialize(headerBuffer, header); ReadOnlySpan <byte> headerBytes = headerBuffer.WrittenSpan; ushort headerLength = (ushort)headerBytes.Length; BinaryPrimitives.WriteUInt16LittleEndian(headerLengthBytes, headerLength); ushort dtoNameLength = (ushort)dtoNameBuffer.Length; BinaryPrimitives.WriteUInt16LittleEndian(dtoNameLengthBytes, dtoNameLength); ushort dtoLength = (ushort)dtoBuffer.Length; BinaryPrimitives.WriteUInt16LittleEndian(dtoLengthBytes, dtoLength); switch (header.Mode) { case CryptoDtoMode.ChaCha20Poly1305: { int adLength = 2 + headerLength; int aeLength = 2 + dtoNameLength + 2 + dtoLength; // Copy data into associated data buffer adBuffer.Clear(); adBuffer.Write(headerLengthBytes); adBuffer.Write(headerBytes); // Copy data into authenticated encryption buffer aeBuffer.Clear(); aeBuffer.Write(dtoNameLengthBytes); aeBuffer.Write(dtoNameBuffer); aeBuffer.Write(dtoLengthBytes); aeBuffer.Write(dtoBuffer); Span <byte> nonceSpan = new Span <byte>(nonceBytes); BinaryPrimitives.WriteUInt64LittleEndian(nonceSpan.Slice(4), header.Sequence); var adSpan = adBuffer.WrittenSpan; var aeSpan = aeBuffer.WrittenSpan; var cipherTextSpan = cipherText.Span.Slice(0, aeLength); cipherTextSpan.Clear(); Span <byte> tagSpan = tagBuffer; tagSpan.Clear(); crypto.Encrypt(nonceSpan, aeSpan, cipherTextSpan, tagSpan, adSpan); output.Write(adSpan); output.Write(cipherTextSpan); output.Write(tagSpan); break; } default: throw new CryptographicException("Mode not recognised"); } } }
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 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); }