/// <summary> /// Create a signature from the input file and secret key provided. /// </summary> /// <param name="fileName"> /// The filename of the target for which to generate the signature /// for. /// </param> /// <param name="keyIn"> /// The secret keyfile input stream. /// </param> /// <param name="signatureStream"> /// The file to which the signature shall be written to. /// </param> /// <param name="pass"> /// The password for the secret key. /// </param> /// <param name="armor"> /// Should the signature be generated as ASCII armor? /// </param> /// <returns> /// The <see cref="PgpSignature"/>. /// </returns> public static PgpSignature CreateDetachedFileSignature( string fileName, Stream keyIn, Stream signatureStream, char[] pass, bool armor) { if (armor) { signatureStream = new ArmoredOutputStream(signatureStream); } var secretKey = PgpKeyHelper.ReadSecretKey(keyIn); var privateKey = secretKey.ExtractPrivateKey(pass); var signatureGenerator = new PgpSignatureGenerator(secretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1); signatureGenerator.InitSign(PgpSignature.BinaryDocument, privateKey); var packetOutputStream = new BcpgOutputStream(signatureStream); using (var fileInputStream = File.OpenRead(fileName)) { int read; var buffer = new byte[PgpCommon.BufferSize]; while ((read = fileInputStream.Read(buffer, 0, buffer.Length)) > 0) { signatureGenerator.Update(buffer, 0, read); } } var signature = signatureGenerator.Generate(); signature.Encode(packetOutputStream); if (armor) { signatureStream.Dispose(); } return(signature); }
/// <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); }
/// <summary> /// Encrypt a file as specified by the input file path. /// </summary> /// <param name="inputFile"> /// The file to encrypt. /// </param> /// <param name="outputFile"> /// The file to write the encrypted content to. /// </param> /// <param name="publicKeyFile"> /// The path to the public key file to use for encryption. /// </param> /// <param name="symmetricKeyAlgorithm"> /// Encryption algorithm. /// </param> /// <param name="armor"> /// Should the encrypted file be written using ASCII armor? /// </param> /// <param name="withIntegrityCheck"> /// Should the integrity be verified? /// </param> /// <param name="compressionAlgorithm"> /// Compression algorithm to use. /// </param> public static void EncryptFile( string inputFile, string outputFile, string publicKeyFile, SymmetricKeyAlgorithmTag symmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.Aes256, bool armor = true, bool withIntegrityCheck = true, CompressionAlgorithmTag compressionAlgorithm = CompressionAlgorithmTag.Zip) { try { using (Stream publicKeyStream = File.OpenRead(publicKeyFile)) { PgpPublicKey encKey = PgpKeyHelper.ReadPublicKey(publicKeyStream); using (var memoryStream = new MemoryStream()) { var compressedDataGenerator = new PgpCompressedDataGenerator(compressionAlgorithm); WriteFileToLiteralData( compressedDataGenerator.Open(memoryStream), PgpLiteralData.Binary, new FileInfo(inputFile)); compressedDataGenerator.Close(); var encryptedDataGenerator = new PgpEncryptedDataGenerator( symmetricKeyAlgorithm, withIntegrityCheck, new SecureRandom()); encryptedDataGenerator.AddMethod(encKey); var bytes = memoryStream.ToArray(); using (Stream outputStream = File.Create(outputFile)) { if (armor) { using (var armoredStream = new ArmoredOutputStream(outputStream)) using (var encryptedStream = encryptedDataGenerator.Open(armoredStream, bytes.Length)) { encryptedStream.Write(bytes, 0, bytes.Length); } } else { using ( Stream encryptedOutputStream = encryptedDataGenerator.Open( outputStream, bytes.Length)) { encryptedOutputStream.Write(bytes, 0, bytes.Length); } } } } } } catch (PgpException exception) { PgpCommon.DumpException(exception); throw; } }