/// <summary> /// Wraps the given read-stream in a CryptoStream and provides the metadata used to create /// that stream. /// </summary> /// <param name="plaintext">Stream to wrap.</param> /// <param name="async">Whether to wrap the content encryption key asynchronously.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The wrapped stream to read from and the encryption metadata for the wrapped stream.</returns> public async Task <(Stream ciphertext, EncryptionData encryptionData)> EncryptInternal( Stream plaintext, bool async, CancellationToken cancellationToken) { if (_keyEncryptionKey == default || _keyWrapAlgorithm == default) { throw Errors.ClientSideEncryption.MissingRequiredEncryptionResources(nameof(_keyEncryptionKey), nameof(_keyWrapAlgorithm)); } var generatedKey = CreateKey(Constants.ClientSideEncryption.EncryptionKeySizeBits); EncryptionData encryptionData = default; Stream ciphertext = default; using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider() { Key = generatedKey }) { encryptionData = await EncryptionData.CreateInternalV1_0( contentEncryptionIv : aesProvider.IV, keyWrapAlgorithm : _keyWrapAlgorithm, contentEncryptionKey : generatedKey, keyEncryptionKey : _keyEncryptionKey, async : async, cancellationToken : cancellationToken).ConfigureAwait(false); ciphertext = new CryptoStream( plaintext, aesProvider.CreateEncryptor(), CryptoStreamMode.Read); } return(ciphertext, encryptionData); }
/// <summary> /// Creates <see cref="EncryptionData"/> from this instance data and a given AES provider. /// </summary> private async Task <EncryptionData> CreateEncryptionDataInternal( AesCryptoServiceProvider aesProvider, bool async, CancellationToken cancellationToken) => await EncryptionData.CreateInternalV1_0( contentEncryptionIv : aesProvider.IV, keyWrapAlgorithm : _keyWrapAlgorithm, contentEncryptionKey : aesProvider.Key, keyEncryptionKey : _keyEncryptionKey, async : async, cancellationToken : cancellationToken).ConfigureAwait(false);
/// <summary> /// Encrypts the given stream and provides the metadata used to encrypt. This method writes to a memory stream, /// optimized for known-size data that will already be buffered in memory. /// </summary> /// <param name="plaintext">Stream to encrypt.</param> /// <param name="async">Whether to wrap the content encryption key asynchronously.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The encrypted data and the encryption metadata for the wrapped stream.</returns> public async Task <(byte[] ciphertext, EncryptionData encryptionData)> BufferedEncryptInternal( Stream plaintext, bool async, CancellationToken cancellationToken) { if (_keyEncryptionKey == default || _keyWrapAlgorithm == default) { throw Errors.ClientSideEncryption.MissingRequiredEncryptionResources(nameof(_keyEncryptionKey), nameof(_keyWrapAlgorithm)); } var generatedKey = CreateKey(Constants.ClientSideEncryption.EncryptionKeySizeBits); EncryptionData encryptionData = default; var ciphertext = new MemoryStream(); byte[] bufferedCiphertext = default; using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider() { Key = generatedKey }) { encryptionData = await EncryptionData.CreateInternalV1_0( contentEncryptionIv : aesProvider.IV, keyWrapAlgorithm : _keyWrapAlgorithm, contentEncryptionKey : generatedKey, keyEncryptionKey : _keyEncryptionKey, async : async, cancellationToken : cancellationToken).ConfigureAwait(false); var transformStream = new CryptoStream( ciphertext, aesProvider.CreateEncryptor(), CryptoStreamMode.Write); if (async) { await plaintext.CopyToAsync(transformStream).ConfigureAwait(false); } else { plaintext.CopyTo(transformStream); } transformStream.FlushFinalBlock(); bufferedCiphertext = ciphertext.ToArray(); } return(bufferedCiphertext, encryptionData); }