Exemple #1
0
        /// <summary>
        /// Build PGP-encrypting (raw/binary format) stream around the provided output stream
        /// </summary>
        /// <param name="publickeysource">Input stream containing public keyring bundle</param>
        /// <param name="publickeyuserid">UserID of key to be used within keyring bundle (if null/empty, first available key in ring will be used)</param>
        /// <param name="encryptedoutput">Output stream to receive raw/binary encrypted data</param>
        /// <returns>
        /// A StreamStack object, into which cleartext data can be written (resulting in encrypted data being written to encryptedoutput)
        /// </returns>
        /// <remarks>
        /// - Caller is responsible for disposing of returned StreamStack (BEFORE disposing of original encryptedoutput Stream)
        /// - Caller is also still responsible for disposing of encryptedinput stream (AFTER disposing of returned StreamStack)
        /// </remarks>
        public static async Task <StreamStack> GetEncryptionStreamRaw(Stream publickeysource, string publickeyuserid, Stream encryptedoutput)
        {
            var encryptionstream = new StreamStack();

            try
            {
                // Create encrypted data generator using public key extracted from provided source:
                var pgpEncDataGen = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Aes256, true, new SecureRandom());
                pgpEncDataGen.AddMethod(await ExtractPublicKey(publickeysource, publickeyuserid));

                // Create encrypted data generator stream around destination stream and push on to return value stack:
                encryptionstream.PushStream(pgpEncDataGen.Open(encryptedoutput, new byte[1024]));

                // Create compressed data generator stream around encryption stream and push on to return value stack:
                var comData = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
                encryptionstream.PushStream(comData.Open(encryptionstream.GetStream()));

                // Create literal data generator stream around compression stream and push on to return value stack:
                var lData = new PgpLiteralDataGenerator();
                encryptionstream.PushStream(lData.Open(encryptionstream.GetStream(), PgpLiteralData.Binary, string.Empty, DateTime.UtcNow, new byte[1024]));

                // Return stream object (data written to stream at top of stack will be literalized -> compressed -> encrypted):
                return(encryptionstream);
            }
            catch
            {
                encryptionstream.Dispose();
                throw;
            }
        }
Exemple #2
0
        /// <summary>
        /// Create PGP-decrypting stream around a PGP-encrypted input source 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>
        /// <returns>
        /// A StreamStack object, from which decrypted data can be read
        /// </returns>
        /// <remarks>
        /// - Caller is responsible for disposing of returned StreamStack (BEFORE disposing of original encryptedinput Stream)
        /// - Caller is also still responsible for disposing of encryptedinput stream (AFTER disposing of returned StreamStack)
        /// - 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 <StreamStack> GetDecryptionStream(Stream privatekeysource, string privatekeypassphrase, Stream encryptedinput)
        {
            var decryptionstream = new StreamStack();

            try
            {
                // Open decoder stream and push on to return value stack:
                decryptionstream.PushStream(PgpUtilities.GetDecoderStream(encryptedinput));

                // Create object factory (using stream at top of stack) to extract encrypted data:
                var factory       = new PgpObjectFactory(decryptionstream.GetStream());
                var encrypteddata = factory.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 and push on to return value stack:
                decryptionstream.PushStream(encrypteddata.GetDataStream(await ExtractPrivateKey(privatekeysource, privatekeypassphrase, encrypteddata.KeyId)));

                // Create new factory from clear stream and extract first PGP object:
                factory = new PgpObjectFactory(decryptionstream.GetStream());
                var message = factory.NextPgpObject();
                while (message != null)
                {
                    // If object is literal data, push de-literalization stream on to return value stack and return:
                    if (message is PgpLiteralData cleardata)
                    {
                        decryptionstream.PushStream(cleardata.GetInputStream());
                        return(decryptionstream);
                    }
                    // Otherwise if this is compressed data, we need to push decompression stream on to return value
                    // stack, then create a new object factory to extract data from decompressed source:
                    else if (message is PgpCompressedData compresseddata)
                    {
                        decryptionstream.PushStream(compresseddata.GetDataStream());
                        factory = new PgpObjectFactory(decryptionstream.GetStream());
                    }

                    // Extract next message object from factory and continue:
                    message = factory.NextPgpObject();
                }

                // If this point is reached, no literal packet was ever found
                throw new ArgumentException("Invalid PGP data (no payload found)");
            }
            catch
            {
                decryptionstream.Dispose();
                throw;
            }
        }