From 7df6d67a7d0dfc4d10df57eeacbeb38298bc3cc5 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Tue, 19 Feb 2019 15:57:11 +0000 Subject: [PATCH 1/6] Add method to encrypt using multiple public key streams --- PgpCore/PGP.cs | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index a401966..4461f30 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -180,23 +180,46 @@ public void EncryptFile( } } + /// + /// PGP Encrypt the stream. + /// + /// + /// + /// + /// + /// + public void EncryptStream( + Stream inputStream, + Stream outputStream, + Stream publicKeyStream, + bool armor = true, + bool withIntegrityCheck = true) + { + EncryptStream(inputStream, outputStream, new[] { publicKeyStream }, armor, withIntegrityCheck); + } + /// /// PGP Encrypt the stream. /// /// /// - /// + /// /// /// - public void EncryptStream(Stream inputStream, Stream outputStream, Stream publicKeyStream, bool armor = true, bool withIntegrityCheck = true) + public void EncryptStream(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, bool armor = true, bool withIntegrityCheck = true) { + //Avoid multiple enumerations of 'publicKeyFilePaths' + Stream[] publicKeys = publicKeyStreams.ToArray(); + if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); - + foreach (Stream publicKey in publicKeys) + { + if (publicKey == null) + throw new ArgumentException("PublicKeyStream"); + } using (MemoryStream @out = new MemoryStream()) { @@ -210,7 +233,11 @@ public void EncryptStream(Stream inputStream, Stream outputStream, Stream public Utilities.WriteStreamToLiteralData(@out, FileTypeToChar(), inputStream, "name"); PgpEncryptedDataGenerator pk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithm, withIntegrityCheck, new SecureRandom()); - pk.AddMethod(Utilities.ReadPublicKey(publicKeyStream)); + + foreach (Stream publicKey in publicKeys) + { + pk.AddMethod(Utilities.ReadPublicKey(publicKey)); + } byte[] bytes = @out.ToArray(); From fe7d43a0752bb49113c8b134e861fc47d1ea3680 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Tue, 19 Feb 2019 15:59:02 +0000 Subject: [PATCH 2/6] Add async methods for multiple public keys --- PgpCore/PGP.cs | 12 ++++++++++++ PgpCoreTest/Program.cs | 21 +++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index 4461f30..e89fe65 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -78,12 +78,24 @@ public async Task EncryptFileAsync(string inputFilePath, string outputFilePath, await Task.Run(() => EncryptFile(inputFilePath, outputFilePath, publicKeyFilePath, armor, withIntegrityCheck)); } + public async Task EncryptFileAsync(string inputFilePath, string outputFilePath, IEnumerable publicKeyFilePaths, + bool armor = true, bool withIntegrityCheck = true) + { + await Task.Run(() => EncryptFile(inputFilePath, outputFilePath, publicKeyFilePaths, armor, withIntegrityCheck)); + } + public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, bool armor = true, bool withIntegrityCheck = true) { await Task.Run(() => EncryptStream(inputStream, outputStream, publicKeyStream, armor, withIntegrityCheck)); } + public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, + bool armor = true, bool withIntegrityCheck = true) + { + await Task.Run(() => EncryptStream(inputStream, outputStream, publicKeyStreams, armor, withIntegrityCheck)); + } + /// /// PGP Encrypt the file. /// diff --git a/PgpCoreTest/Program.cs b/PgpCoreTest/Program.cs index c64bbea..6db6f09 100644 --- a/PgpCoreTest/Program.cs +++ b/PgpCoreTest/Program.cs @@ -1,6 +1,7 @@ using PgpCore; using System; using System.IO; +using System.Text; namespace PgpCoreTest { @@ -73,6 +74,26 @@ static void Main(string[] args) } } } + + // Encrypt key and sign stream + using (Stream inputFileStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("Streaming signed test message"))) + { + using (Stream publicKeyStream = new FileStream(@"C:\TEMP\keys\public.asc", FileMode.Open)) + { + using (Stream privateKeyStream = new FileStream(@"C:\TEMP\keys\private.asc", FileMode.Open)) + { + using (Stream encryptedMemoryStream = new MemoryStream()) + { + pgp.EncryptStreamAndSign(inputFileStream, encryptedMemoryStream, publicKeyStream, privateKeyStream, "password"); + // Reset stream to beginning + encryptedMemoryStream.Seek(0, SeekOrigin.Begin); + StreamReader encryptedReader = new StreamReader(encryptedMemoryStream); + string encryptedText = encryptedReader.ReadToEnd(); + Console.WriteLine(encryptedText); + } + } + } + } } } } From 3506cc5c3233c859cc64d579bd95ea62355b6345 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Tue, 19 Feb 2019 17:56:22 +0000 Subject: [PATCH 3/6] Allow multiple public keys --- PgpCore/EncryptionKeys.cs | 56 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/PgpCore/EncryptionKeys.cs b/PgpCore/EncryptionKeys.cs index 085452a..e4a5d02 100644 --- a/PgpCore/EncryptionKeys.cs +++ b/PgpCore/EncryptionKeys.cs @@ -13,6 +13,7 @@ internal sealed class EncryptionKeys #region Instance Members (Public) public PgpPublicKey PublicKey { get; private set; } + public IEnumerable PublicKeys { get; private set; } public PgpPrivateKey PrivateKey { get; private set; } public PgpSecretKey SecretKey { get; private set; } @@ -48,6 +49,41 @@ public EncryptionKeys(string publicKeyFilePath, string privateKeyFilePath, strin PrivateKey = ReadPrivateKey(passPhrase); } + /// + /// 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. + /// + /// The key used to encrypt the data + /// The key used to sign the data. + /// The password required to access the private key + /// Public key not found. Private key not found. Missing password + public EncryptionKeys(IEnumerable publicKeyFilePaths, string privateKeyFilePath, string passPhrase) + { + //Avoid multiple enumerations of 'publicKeyFilePaths' + string[] publicKeys = publicKeyFilePaths.ToArray(); + + if (String.IsNullOrEmpty(privateKeyFilePath)) + throw new ArgumentException("PrivateKeyFilePath"); + if (passPhrase == null) + throw new ArgumentNullException("Invalid Pass Phrase."); + + if (!File.Exists(privateKeyFilePath)) + throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); + + foreach (string publicKeyFilePath in publicKeys) + { + if (String.IsNullOrEmpty(publicKeyFilePath)) + throw new ArgumentException(nameof(publicKeyFilePath)); + if (!File.Exists(publicKeyFilePath)) + throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", publicKeyFilePath)); + } + + PublicKeys = publicKeys.Select(x => Utilities.ReadPublicKey(x)).ToList(); + SecretKey = ReadSecretKey(privateKeyFilePath); + PrivateKey = ReadPrivateKey(passPhrase); + } + public EncryptionKeys(Stream publicKeyStream, Stream privateKeyStream, string passPhrase) { if (publicKeyStream == null) @@ -62,6 +98,26 @@ public EncryptionKeys(Stream publicKeyStream, Stream privateKeyStream, string pa PrivateKey = ReadPrivateKey(passPhrase); } + public EncryptionKeys(IEnumerable publicKeyStreams, Stream privateKeyStream, string passPhrase) + { + //Avoid multiple enumerations of 'publicKeyFilePaths' + Stream[] publicKeys = publicKeyStreams.ToArray(); + + if (privateKeyStream == null) + throw new ArgumentException("PrivateKeyStream"); + if (passPhrase == null) + throw new ArgumentNullException("Invalid Pass Phrase."); + foreach (Stream publicKey in publicKeys) + { + if (publicKey == null) + throw new ArgumentException("PublicKeyStream"); + } + + PublicKeys = publicKeys.Select(x => Utilities.ReadPublicKey(x)).ToList(); + SecretKey = ReadSecretKey(privateKeyStream); + PrivateKey = ReadPrivateKey(passPhrase); + } + #endregion Constructors #region Secret Key From 283ecc5ab940705df4b69ed3cfca2eeeae4771a2 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Tue, 19 Feb 2019 17:57:18 +0000 Subject: [PATCH 4/6] Add encrypt and sign method that takes multiple public keys --- PgpCore/PGP.cs | 86 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index e89fe65..c775974 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -283,11 +283,22 @@ public async Task EncryptFileAndSignAsync(string inputFilePath, string outputFil await Task.Run(() => EncryptFileAndSign(inputFilePath, outputFilePath, publicKeyFilePath, privateKeyFilePath, passPhrase, armor, withIntegrityCheck)); } + public async Task EncryptFileAndSignAsync(string inputFilePath, string outputFilePath, IEnumerable publicKeyFilePaths, string privateKeyFilePath, + string passPhrase, bool armor = true, bool withIntegrityCheck = true) + { + await Task.Run(() => EncryptFileAndSign(inputFilePath, outputFilePath, publicKeyFilePaths, privateKeyFilePath, passPhrase, armor, withIntegrityCheck)); + } + public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true) { await Task.Run(() => EncryptStreamAndSign(inputStream, outputStream, publicKeyStream, privateKeyStream, passPhrase, armor, withIntegrityCheck)); } + public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true) + { + await Task.Run(() => EncryptStreamAndSign(inputStream, outputStream, publicKeyStreams, privateKeyStream, passPhrase, armor, withIntegrityCheck)); + } + /// /// Encrypt and sign the file pointed to by unencryptedFileInfo and /// @@ -300,12 +311,28 @@ public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStr public void EncryptFileAndSign(string inputFilePath, string outputFilePath, string publicKeyFilePath, string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true) { + EncryptFileAndSign(inputFilePath, outputFilePath, new[] { publicKeyFilePath }, privateKeyFilePath, passPhrase, armor, withIntegrityCheck); + } + + /// + /// Encrypt and sign the file pointed to by unencryptedFileInfo and + /// + /// + /// + /// + /// + /// + /// + public void EncryptFileAndSign(string inputFilePath, string outputFilePath, IEnumerable publicKeyFilePaths, + string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true) + { + //Avoid multiple enumerations of 'publicKeyFilePaths' + string[] publicKeys = publicKeyFilePaths.ToArray(); + if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(publicKeyFilePath)) - throw new ArgumentException("PublicKeyFilePath"); if (String.IsNullOrEmpty(privateKeyFilePath)) throw new ArgumentException("PrivateKeyFilePath"); if (passPhrase == null) @@ -313,12 +340,18 @@ public void EncryptFileAndSign(string inputFilePath, string outputFilePath, stri if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key file [{0}] does not exist.", publicKeyFilePath)); if (!File.Exists(privateKeyFilePath)) throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyFilePath, privateKeyFilePath, passPhrase); + foreach (string publicKeyFilePath in publicKeys) + { + if (String.IsNullOrEmpty(publicKeyFilePath)) + throw new ArgumentException(nameof(publicKeyFilePath)); + if (!File.Exists(publicKeyFilePath)) + throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", publicKeyFilePath)); + } + + EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyFilePaths, privateKeyFilePath, passPhrase); if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -342,25 +375,44 @@ public void EncryptFileAndSign(string inputFilePath, string outputFilePath, stri /// /// /// - /// - /// + /// + /// /// /// public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true) + { + EncryptStreamAndSign(inputStream, outputStream, new[] { publicKeyStream }, privateKeyStream, passPhrase, armor, withIntegrityCheck); + } + + /// + /// Encrypt and sign the stream pointed to by unencryptedFileInfo and + /// + /// + /// + /// + /// + /// + /// + public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, + Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); if (privateKeyStream == null) throw new ArgumentException("PrivateKeyStream"); if (passPhrase == null) passPhrase = String.Empty; - EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyStream, privateKeyStream, passPhrase); + foreach (Stream publicKey in publicKeyStreams) + { + if (publicKey == null) + throw new ArgumentException("PublicKeyStream"); + } + + EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyStreams, privateKeyStream, passPhrase); if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -440,7 +492,19 @@ private Stream ChainEncryptedOut(Stream outputStream, EncryptionKeys encryptionK { PgpEncryptedDataGenerator encryptedDataGenerator; encryptedDataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithm, withIntegrityCheck, new SecureRandom()); - encryptedDataGenerator.AddMethod(encryptionKeys.PublicKey); + + if (encryptionKeys.PublicKey != null) + { + encryptedDataGenerator.AddMethod(encryptionKeys.PublicKey); + } + else if (encryptionKeys.PublicKeys != null) + { + foreach (PgpPublicKey publicKey in encryptionKeys.PublicKeys) + { + encryptedDataGenerator.AddMethod(publicKey); + } + } + return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]); } From 816f632012f1513a7e0b7e16e588f69c7bb01ed9 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Wed, 20 Feb 2019 16:46:09 +0000 Subject: [PATCH 5/6] Update tests --- PgpCoreTest/Program.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PgpCoreTest/Program.cs b/PgpCoreTest/Program.cs index 6db6f09..5119dac 100644 --- a/PgpCoreTest/Program.cs +++ b/PgpCoreTest/Program.cs @@ -21,6 +21,8 @@ static void Main(string[] args) pgp.EncryptFile(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted_multiple.pgp", publicKeys, true, true); // Encrypt and sign file pgp.EncryptFileAndSign(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "password", true, true); + // Encrypt and sign multiple file + pgp.EncryptFileAndSign(@"C:\TEMP\keys\content.txt", @"C:\TEMP\keys\content__encrypted_signed_multiple.pgp", publicKeys, @"C:\TEMP\keys\private.asc", "password", true, true); // Decrypt file pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted.pgp", @"C:\TEMP\keys\content__decrypted.txt", @"C:\TEMP\keys\private.asc", "password"); // Decrypt multiple file @@ -28,6 +30,9 @@ static void Main(string[] args) pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_multiple.pgp", @"C:\TEMP\keys\content__decrypted_multiple2.txt", @"C:\TEMP\keys\private2.asc", "password2"); // Decrypt signed file pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_signed.pgp", @"C:\TEMP\keys\content__decrypted_signed.txt", @"C:\TEMP\keys\private.asc", "password"); + // Decrypt signed multiple file + pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_signed_multiple.pgp", @"C:\TEMP\keys\content__decrypted_signed_multiple.txt", @"C:\TEMP\keys\private.asc", "password"); + pgp.DecryptFile(@"C:\TEMP\keys\content__encrypted_signed_multiple.pgp", @"C:\TEMP\keys\content__decrypted_signed_multiple2.txt", @"C:\TEMP\keys\private2.asc", "password2"); // Encrypt stream using (FileStream inputFileStream = new FileStream(@"C:\TEMP\keys\content.txt", FileMode.Open)) From 392adc4d00fee636e198ba963b3710300d4857d4 Mon Sep 17 00:00:00 2001 From: mattosaurus Date: Wed, 20 Feb 2019 16:47:39 +0000 Subject: [PATCH 6/6] Update version --- PgpCore/PgpCore.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PgpCore/PgpCore.csproj b/PgpCore/PgpCore.csproj index d3b90ce..e1103d2 100644 --- a/PgpCore/PgpCore.csproj +++ b/PgpCore/PgpCore.csproj @@ -11,9 +11,9 @@ https://github.com/mattosaurus/PgpCore PGP .NET Core 1.3.1 - 1.3.1.0 - 1.3.1.0 - ReadPublicKey moved to Utilities + 1.4.0.0 + 1.4.0.0 + Allow encrypt and sign with multiple keys