Beispiel #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);
            }
        }
 /// <summary>
 /// Create a new instance with a default buffer length of 128KB.
 /// </summary>
 /// <param name="stream">When encrypting, the stream to write the ciphertext to. When decrypting, the stream to read the ciphertext from.</param>
 /// <param name="key">The encryption key.</param>
 /// <param name="encryptionMode">Whether the stream will be used for encryption or decryption.</param>
 /// <param name="leaveOpen">Whether to leave the <paramref name="stream"/> open.</param>
 public XChaChaBufferedStream(
     Stream stream,
     XChaChaKey key,
     EncryptionMode encryptionMode,
     bool leaveOpen = false)
     : base(stream, key, encryptionMode, leaveOpen)
 {
     this.plaintextBuffer  = new RentedArray(DefaultPlaintextBufferLength);
     this.ciphertextBuffer = new RentedArray(CalculateCiphertextLength(DefaultPlaintextBufferLength));
 }
Beispiel #3
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));
                }
            }
        }