/// <summary> /// Decrypt file and verify file signature from stream. /// </summary> /// <param name="inputStream"> /// The encrypted data input stream. /// </param> /// <param name="outputStream"> /// The output stream. /// </param> /// <param name="privateKeyStream"> /// The private key stream. /// </param> /// <param name="publicKeyStream"> /// The public key stream. /// </param> /// <param name="passPhrase"> /// The pass phrase. /// </param> /// <returns> /// The <see cref="bool"/> value indicating whether or not the signature in /// the decrypted data is valid. /// </returns> public static bool DecryptAndVerifyStream( Stream inputStream, Stream outputStream, Stream privateKeyStream, Stream publicKeyStream, char[] passPhrase) { PgpPrivateKey privateKey = null; PgpPublicKeyEncryptedData encryptedData = null; var secretKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); var encryptedDataList = GetEncryptedDataListFromStream(inputStream); foreach (PgpPublicKeyEncryptedData dataObject in encryptedDataList.GetEncryptedDataObjects()) { privateKey = PgpKeyHelper.FindSecretKey(secretKeyRing, dataObject.KeyId, passPhrase); if (privateKey == null) { continue; } encryptedData = dataObject; break; } if (privateKey == null) { throw new Exception("Unable to find secret key to decrypt the message"); } var valid = ProcessDecryptionMessageBlocks(encryptedData, outputStream, publicKeyStream, privateKey); if (encryptedData.IsIntegrityProtected() && !encryptedData.Verify()) { throw new PgpException("Data is integrity protected but integrity is lost."); } return(valid); }
/// <summary> /// Decrypt a stream using the private key stream. /// </summary> /// <param name="inputStream"> /// The stream of the encrypted file. /// </param> /// <param name="privateKeyStream"> /// The stream of the private key file. /// </param> /// <param name="passPhrase"> /// The pass phrase protecting the secret key. /// </param> /// <param name="outputFile"> /// The file path to write the decrypted output to. /// </param> /// <returns> /// The <see cref="bool"/> flag indicating decryption success; false states /// decryption failed because of a data integrity check error. /// </returns> public static bool DecryptFileStream( Stream inputStream, Stream privateKeyStream, string passPhrase, string outputFile) { PgpPrivateKey privateKey = null; var valid = true; try { PgpEncryptedDataList encryptedDataList; PgpPublicKeyEncryptedData encryptedData = null; var objectFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream)); var secretKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); var @object = objectFactory.NextPgpObject(); if (@object is PgpEncryptedDataList) { encryptedDataList = (PgpEncryptedDataList)@object; } else { encryptedDataList = (PgpEncryptedDataList)objectFactory.NextPgpObject(); } foreach (PgpPublicKeyEncryptedData pked in encryptedDataList.GetEncryptedDataObjects()) { privateKey = PgpKeyHelper.FindSecretKey(secretKeyRing, pked.KeyId, passPhrase.ToCharArray()); if (privateKey == null) { continue; } encryptedData = pked; break; } if (privateKey == null) { throw new ArgumentException("Secret key for message not found."); } PgpObjectFactory plainFact; using (var clear = encryptedData.GetDataStream(privateKey)) { plainFact = new PgpObjectFactory(clear); } var message = plainFact.NextPgpObject(); if (message is PgpCompressedData) { var data = (PgpCompressedData)message; PgpObjectFactory of; using (var compDataIn = data.GetDataStream()) { of = new PgpObjectFactory(compDataIn); } message = of.NextPgpObject(); if (message is PgpOnePassSignatureList) { message = of.NextPgpObject(); var literalData = (PgpLiteralData)message; using (Stream output = File.Create(outputFile)) { var unc = literalData.GetInputStream(); Streams.PipeAll(unc, output); } } else { var literalData = (PgpLiteralData)message; using (Stream output = File.Create(outputFile)) { Stream unc = literalData.GetInputStream(); Streams.PipeAll(unc, output); } } } else if (message is PgpLiteralData) { PgpLiteralData literalData = (PgpLiteralData)message; string unused = literalData.FileName; using (Stream outputStream = File.Create(outputFile)) { Stream unc = literalData.GetInputStream(); Streams.PipeAll(unc, outputStream); } } else if (message is PgpOnePassSignatureList) { throw new PgpException("Encrypted message contains a signed message - not literal data."); } else { throw new PgpException("Message is not a simple encrypted file - type unknown."); } if (encryptedData.IsIntegrityProtected()) { if (!encryptedData.Verify()) { Console.Error.WriteLine("Message failed integrity check"); valid = false; } else { Console.Error.WriteLine("Message integrity check passed"); } } } catch (PgpException exception) { PgpCommon.DumpException(exception); throw; } return(valid); }