Exemple #1
0
        /// <summary>
        /// Decrypts the inner stream and populates <paramref name="destination"/> with the resulting plaintext.
        /// </summary>
        /// <param name="destination">The buffer where the plaintext will be output to.</param>
        /// <param name="additionalData">Additional data to use when verify the authentication tag.</param>
        /// <returns>The number of bytes written to <paramref name="destination"/>.</returns>
        public int Read(Span <byte> destination, ReadOnlySpan <byte> additionalData)
        {
            var inputSize = CalculateCiphertextLength(destination.Length);

            using (var ciphertextBuffer = new RentedArray(inputSize))
            {
                if (!this.CanRead)
                {
                    throw new NotSupportedException();
                }

                var bytesRead     = this.stream.Read(ciphertextBuffer.AsSpan());
                var decryptResult = crypto_secretstream_xchacha20poly1305_pull(
                    this.state.Handle,
                    ref MemoryMarshal.GetReference(destination),
                    out var decryptedBlockLongLength,
                    out var tag,
                    in MemoryMarshal.GetReference(ciphertextBuffer.AsReadOnlySpan()),
                    (UInt64)bytesRead,
                    ref MemoryMarshal.GetReference(additionalData),
                    (UInt64)additionalData.Length);

                if (decryptResult != 0)
                {
                    throw new CryptographicException("block is invalid or corrupt");
                }
                this.tagOfLastDecryptedBlock = tag;

                return((int)decryptedBlockLongLength);
            }
        }
Exemple #2
0
        private void EncryptBlock(ReadOnlySpan <byte> source, ReadOnlySpan <byte> additionalData, byte tag)
        {
            if (!this.CanWrite)
            {
                throw new NotSupportedException();
            }

            if (!this.headerWritten)
            {
                this.WriteHeader();
            }

            var count = source.Length;

            if (count > 0)
            {
                var outputSize = CalculateCiphertextLength(count);
                using (var ciphertextBuffer = new RentedArray(outputSize))
                {
                    var encryptionResult = crypto_secretstream_xchacha20poly1305_push(
                        this.state.Handle,
                        ref MemoryMarshal.GetReference(ciphertextBuffer.AsSpan()),
                        out var ciphertextLength,
                        in MemoryMarshal.GetReference(source),
                        (ulong)count,
                        ref MemoryMarshal.GetReference(additionalData),
                        (UInt64)additionalData.Length,
                        tag);

                    if (encryptionResult != 0)
                    {
                        throw new CryptographicException("encryption of block failed");
                    }

                    this.stream.Write(ciphertextBuffer.AsReadOnlySpan(0, (int)ciphertextLength));
                }
            }
        }