Example #1
0
        //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");
                }
            }
        }
Example #2
0
            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");
                }
            }
Example #3
0
        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);
        }