Hello, I'm attempting (in C#) to encrypt a Stream object instead of using a FileInfo object. I have attached my source code below. Any help would be appreciated.
Thanks!
using Org.BouncyCastle.Bcpg; using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Security; using System; using System.IO; /// Code is provided as-is, as-written. I'm not an expert in cryptography, and I don't plan /// on releasing updates. Please review prior to using in anything critical. /// Steve Ledwith - st...@ledwith.org - http://ledwith.org /// Released under GPLv3 - Please contact me if you have any questions. namespace SPL.Crypto { /// <summary> /// Wrapper around Bouncy Castle OpenPGP library. /// Bouncy documentation can be found here: http://www.bouncycastle.org/docs/pgdocs1.6/index.html /// Code from: http://blogs.microsoft.co.il/blogs/kim/archive/2009/01/23/pgp-zip-encrypted-files-with-c.aspx /// with some very minor changes. /// </summary> public class PgpEncrypt { #region Private Variables private PgpEncryptionKeys mEncryptionKeys; private const int bufferSize = 0x10000; // should always be power of 2 #endregion #region Public Methods /// <summary> /// Instantiate a new PgpEncrypt class with initialized PgpEncryptionKeys. /// </summary> /// <param name="encryptionKeys"></param> /// <exception cref="ArgumentNullException">encryptionKeys is null</exception> public PgpEncrypt(PgpEncryptionKeys encryptionKeys) { if (encryptionKeys == null) { throw new ArgumentNullException("encryptionKeys", "encryptionKeys is null."); } mEncryptionKeys = encryptionKeys; } /// <summary> /// Encrypt and sign the file pointed to by unencryptedFileInfo and /// write the encrypted content to outputStream. /// </summary> /// <param name="outputStream"> /// The stream that will contain the encrypted data when this method returns. /// </param> /// <param name="fileName">FileInfo of the file to encrypt</param> public void EncryptAndSign(Stream outputStream, FileInfo unencryptedFileInfo) { if (outputStream == null) { throw new ArgumentNullException("outputStream", "outputStream is null."); } if (unencryptedFileInfo == null) { throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo is null."); } if (!File.Exists(unencryptedFileInfo.FullName)) { throw new ArgumentException("File to encrypt not found."); } using (Stream encryptedOut = chainEncryptedOut(outputStream)) { using (Stream compressedOut = chainCompressedOut(encryptedOut)) { PgpSignatureGenerator signatureGenerator = initSignatureGenerator(compressedOut); using (Stream literalOut = chainLiteralOut(compressedOut, unencryptedFileInfo)) { using (FileStream inputFile = unencryptedFileInfo.OpenRead()) { writeOutputAndSign(compressedOut, literalOut, inputFile, signatureGenerator); } } } } } public void EncryptAndSignStream(Stream outputStream, Stream inStream) { if (outputStream == null) { throw new ArgumentNullException("outputStream", "outputStream is null."); } //if (unencryptedFileInfo == null) //{ // throw new ArgumentNullException("unencryptedFileInfo", "unencryptedFileInfo is null."); //} //if (!File.Exists(unencryptedFileInfo.FullName)) //{ // throw new ArgumentException("File to encrypt not found."); //} using (Stream encryptedOut = chainEncryptedOut(outputStream)) { using (Stream compressedOut = chainCompressedOut(encryptedOut)) { PgpSignatureGenerator signatureGenerator = initSignatureGenerator(compressedOut); using (Stream literalOut = chainLiteralOutStream(compressedOut, inStream)) { //using (FileStream inputFile = inStream.OpenRead()) //{ // writeOutputAndSign(compressedOut, literalOut, inputFile, signatureGenerator); //} writeOutputAndSignStream(compressedOut, literalOut, inStream, signatureGenerator); } } } } #endregion #region Private Methods private static void writeOutputAndSign(Stream compressedOut, Stream literalOut, FileStream inputFile, PgpSignatureGenerator signatureGenerator) { int length = 0; byte[] buf = new byte[bufferSize]; while ((length = inputFile.Read(buf, 0, buf.Length)) > 0) { literalOut.Write(buf, 0, length); signatureGenerator.Update(buf, 0, length); } signatureGenerator.Generate().Encode(compressedOut); } private Stream chainEncryptedOut(Stream outputStream) { PgpEncryptedDataGenerator encryptedDataGenerator; encryptedDataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.TripleDes, new SecureRandom()); encryptedDataGenerator.AddMethod(mEncryptionKeys.PublicKey); return encryptedDataGenerator.Open(outputStream, new byte[bufferSize]); } private static Stream chainCompressedOut(Stream encryptedOut) { PgpCompressedDataGenerator compressedDataGenerator = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip); return compressedDataGenerator.Open(encryptedOut); } private static Stream chainLiteralOut(Stream compressedOut, FileInfo file) { PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator(); return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, file); } private PgpSignatureGenerator initSignatureGenerator(Stream compressedOut) { const bool IsCritical = false; const bool IsNested = false; PublicKeyAlgorithmTag tag = mEncryptionKeys.SecretKey.PublicKey.Algorithm; PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag.Sha1); pgpSignatureGenerator.InitSign(PgpSignature.BinaryDocument, mEncryptionKeys.PrivateKey); foreach (string userId in mEncryptionKeys.SecretKey.PublicKey.GetUserIds()) { PgpSignatureSubpacketGenerator subPacketGenerator = new PgpSignatureSubpacketGenerator(); subPacketGenerator.SetSignerUserId(IsCritical, userId); pgpSignatureGenerator.SetHashedSubpackets(subPacketGenerator.Generate()); // Just the first one! break; } pgpSignatureGenerator.GenerateOnePassVersion(IsNested).Encode(compressedOut); return pgpSignatureGenerator; } private static void writeOutputAndSignStream(Stream compressedOut, Stream literalOut, Stream inStream, PgpSignatureGenerator signatureGenerator) { int length = 0; byte[] buf = new byte[bufferSize]; while ((length = inStream.Read(buf, 0, buf.Length)) > 0) { literalOut.Write(buf, 0, length); signatureGenerator.Update(buf, 0, length); } signatureGenerator.Generate().Encode(compressedOut); } private static Stream chainLiteralOutStream(Stream compressedOut, Stream inStream) { PgpLiteralDataGenerator pgpLiteralDataGenerator = new PgpLiteralDataGenerator(); return pgpLiteralDataGenerator.Open(compressedOut, PgpLiteralData.Binary, "filename", DateTime.Now, ReadFully(inStream)); } public static byte[] ReadFully(Stream input) { byte[] buffer = new byte[16 * 1024]; using (MemoryStream ms = new MemoryStream()) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } } #endregion } }
using Org.BouncyCastle.Bcpg.OpenPgp; using System; using System.IO; using System.Linq; using System.Text; /// Code is provided as-is, as-written. I'm not an expert in cryptography, and I don't plan /// on releasing updates. Please review prior to using in anything critical. /// Steve Ledwith - st...@ledwith.org - http://ledwith.org /// Released under GPLv3 - Please contact me if you have any questions. namespace SPL.Crypto { public class PgpEncryptionKeys { #region Public Methods public PgpPublicKey PublicKey { get; private set; } public PgpPrivateKey PrivateKey { get; private set; } public PgpSecretKey SecretKey { get; private set; } /// <summary> /// Initializes a new instance of the EncryptionKeys class. /// Two keys are required to encrypt and sign data. Your private key and the recipients public key. /// The data is encrypted with the recipients public key and signed with your private key. /// </summary> /// <param name="publicKeyPath">The key used to encrypt the data</param> /// <param name="privateKeyPath">The key used to sign the data.</param> /// <param name="passPhrase">The (your) password required to access the private key</param> /// <exception cref="ArgumentException">Public key not found. Private key not found. Missing password</exception> public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase) { if (!File.Exists(publicKeyPath)) { throw new ArgumentException("Public key file not found.", "publicKeyPath"); } if (!File.Exists(privateKeyPath)) { throw new ArgumentException("Private key file not found.", "privateKeyPath"); } if (String.IsNullOrEmpty(passPhrase)) { throw new ArgumentException("passPhrase is null or empty.", "passPhrase"); } PublicKey = readPublicKey(publicKeyPath); SecretKey = readSecretKey(privateKeyPath); PrivateKey = readPrivateKey(passPhrase); } #endregion #region Private Methods #region Secret Key private PgpSecretKey readSecretKey(string privateKeyPath) { using (Stream keyIn = File.OpenRead(privateKeyPath)) { using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn)) { PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream); PgpSecretKey foundKey = getFirstSecretKey(secretKeyRingBundle); if (foundKey != null) { return foundKey; } } } throw new ArgumentException("Can't find signing key in key ring."); } /// <summary> /// Return the first key we can use to encrypt. /// Note: A file can contain multiple keys (stored in "key rings") /// </summary> private PgpSecretKey getFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle) { foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings()) { // Note: You may need to use something other than the first key // in your key ring. Keep that in mind. // ex: .Where(k => !k.IsSigningKey) var a = kRing.GetSecretKeys(); PgpSecretKey key = kRing.GetSecretKeys() .Cast<PgpSecretKey>() .Where(k => k.IsSigningKey) //.Where(k => !k.IsSigningKey) .FirstOrDefault(); if (key != null) { return key; } } return null; } #endregion #region Public Key private PgpPublicKey readPublicKey(string publicKeyPath) { using (Stream keyIn = File.OpenRead(publicKeyPath)) { using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn)) { try { PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRingBundle(inputStream); PgpPublicKey foundKey = getFirstPublicKey(publicKeyRingBundle); if (foundKey != null) { return foundKey; } } catch (Exception) { throw new ArgumentException("There was a problem with the public key ring."); } } } throw new ArgumentException("No encryption key found in public key ring."); } private PgpPublicKey getFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle) { foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings()) { PgpPublicKey key = kRing.GetPublicKeys() .Cast<PgpPublicKey>() .Where(k => k.IsEncryptionKey) .FirstOrDefault(); if (key != null) { return key; } } return null; } #endregion #region Private Key private PgpPrivateKey readPrivateKey(string passPhrase) { PgpPrivateKey privateKey = SecretKey.ExtractPrivateKey(passPhrase.ToCharArray()); if (privateKey != null) { return privateKey; } throw new ArgumentException("No private key found in secret key."); } #endregion #endregion } }