/// <summary> /// PGP-decrypt all data from source stream into destination stream /// </summary> /// <param name="privatekeysource">Input stream containing private keyring bundle</param> /// <param name="privatekeypassphrase">Passphrase to access private key (if required)</param> /// <param name="encryptedinput">Input stream containing source data to be decrypted</param> /// <param name="clearoutput">Output stream to receive decrypted data</param> /// <remarks> /// Destination data stream will be written asynchronously, but source data stream will be read synchronously (due to limitation in PGP /// library; all source data must be available to perform decryption, but source library does not provide async option). If this is a concern, /// caller should consider asynchronously pulling source data into local stream first and passing local stream to this function (if increased /// use of memory outweighs waiting for blocked thread to perform I/O) /// </remarks> public static async Task Decrypt(Stream privatekeysource, string privatekeypassphrase, Stream encryptedinput, Stream clearoutput) { // Create object factory using DecoderStream to read PGP data from source, use factory to extract encrypted data: using (var decoder = PgpUtilities.GetDecoderStream(encryptedinput)) { var encrypteddata = new PgpObjectFactory(decoder).GetEncryptedData() ?? throw new ArgumentException("No PGP-encrypted data found"); // Extract private key from key source (using key ID required by encrypted data object), use to open clear stream: using (var clearsource = encrypteddata.GetDataStream(await ExtractPrivateKey(privatekeysource, privatekeypassphrase, encrypteddata.KeyId))) { // Create new object factory from clear stream and use to write cleartext data to destination: await new PgpObjectFactory(clearsource).WriteClearData(clearoutput); } } }