diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..a551aa1 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,12 @@ + version: 2.1 + + orbs: + win: circleci/windows@2.2.0 + + jobs: + build: + executor: win/default + + steps: + - checkout + - run: dotnet build diff --git a/.gitignore b/.gitignore index 3c4efe2..7866228 100644 --- a/.gitignore +++ b/.gitignore @@ -258,4 +258,5 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc +.vscode/ diff --git a/PgpCore.Tests/PgpCore.Tests.csproj b/PgpCore.Tests/PgpCore.Tests.csproj index 2a4ad9b..9162663 100644 --- a/PgpCore.Tests/PgpCore.Tests.csproj +++ b/PgpCore.Tests/PgpCore.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net472;netcoreapp3.1 false diff --git a/PgpCore.Tests/UnitTests/UnitTestsAsync.cs b/PgpCore.Tests/UnitTests/UnitTestsAsync.cs index 4ecec59..0040a25 100644 --- a/PgpCore.Tests/UnitTests/UnitTestsAsync.cs +++ b/PgpCore.Tests/UnitTests/UnitTestsAsync.cs @@ -11,6 +11,17 @@ namespace PgpCore.Tests { public class UnitTestsAsync { + private static class File + { + public static FileStream Create(string path) => System.IO.File.Create(path); + public static bool Exists(string path) => System.IO.File.Exists(path); +#if NETFRAMEWORK + public static Task ReadAllTextAsync(string path) => Task.FromResult(System.IO.File.ReadAllText(path)); +#else + public static Task ReadAllTextAsync(string path) => System.IO.File.ReadAllTextAsync(path); +#endif + } + [Fact] public async Task GenerateKeyAsync_CreatePublicPrivateKeyFiles() { diff --git a/PgpCore.Tests/UnitTests/UnitTestsSync.cs b/PgpCore.Tests/UnitTests/UnitTestsSync.cs index 460b368..f16654d 100644 --- a/PgpCore.Tests/UnitTests/UnitTestsSync.cs +++ b/PgpCore.Tests/UnitTests/UnitTestsSync.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Security.Cryptography; +using System.Text; using Org.BouncyCastle.Bcpg; using Org.BouncyCastle.Bcpg.OpenPgp; using Xunit; @@ -673,6 +674,31 @@ public void SignStream_CreateSignedFile(KeyType keyType) testFactory.Teardown(); } + [Theory] + [InlineData(KeyType.Generated)] + [InlineData(KeyType.Known)] + [InlineData(KeyType.KnownGpg)] + public void SignStream_CreateSigned_File_From_String(KeyType keyType) + { + // Arrange + TestFactory testFactory = new TestFactory(); + testFactory.Arrange(keyType); + PGP pgp = new PGP(); + + // Act + byte[] byteArray = Encoding.ASCII.GetBytes("The quick brown fox jumps over the lazy dog"); + using (Stream inputFileStream = new MemoryStream(byteArray)) + using (Stream outputFileStream = File.Create(testFactory.EncryptedContentFilePath)) + using (Stream privateKeyStream = new FileStream(testFactory.PrivateKeyFilePath, FileMode.Open)) + pgp.SignStream(inputFileStream, outputFileStream, privateKeyStream, testFactory.Password); + + // Assert + Assert.True(File.Exists(testFactory.EncryptedContentFilePath)); + + // Teardown + testFactory.Teardown(); + } + [Theory] [InlineData(KeyType.Generated)] [InlineData(KeyType.Known)] diff --git a/PgpCore/EncryptionKeys.cs b/PgpCore/EncryptionKeys.cs index 206b210..801e77f 100644 --- a/PgpCore/EncryptionKeys.cs +++ b/PgpCore/EncryptionKeys.cs @@ -3,22 +3,28 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Security; using System.Text; using System.Threading.Tasks; namespace PgpCore { - internal sealed class EncryptionKeys + public class EncryptionKeys : IEncryptionKeys { #region Instance Members (Public) - - public PgpPublicKey PublicKey { get; private set; } + public PgpPublicKey PublicKey => PublicKeys.FirstOrDefault(); public IEnumerable PublicKeys { get; private set; } public PgpPrivateKey PrivateKey { get; private set; } public PgpSecretKey SecretKey { get; private set; } + public PgpSecretKeyRingBundle SecretKeys { get; private set; } #endregion Instance Members (Public) + #region Instance Members (Private) + private readonly string _passPhrase; + + #endregion Instance Members (Private) + #region Constructors /// @@ -44,23 +50,24 @@ public EncryptionKeys(string publicKeyFilePath, string privateKeyFilePath, strin if (!File.Exists(privateKeyFilePath)) throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - PublicKey = Utilities.ReadPublicKey(publicKeyFilePath); + PublicKeys = new List() { Utilities.ReadPublicKey(publicKeyFilePath) }; SecretKey = ReadSecretKey(privateKeyFilePath); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = 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. + /// Two or more keys are required to encrypt and sign data. Your private key and the recipients public key(s). + /// The data is encrypted with the recipients public key(s) and signed with your private key. /// - /// The key used to encrypt the data + /// The key(s) 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' + // Avoid multiple enumerations of 'publicKeyFilePaths' string[] publicKeys = publicKeyFilePaths.ToArray(); if (String.IsNullOrEmpty(privateKeyFilePath)) @@ -82,6 +89,7 @@ public EncryptionKeys(IEnumerable publicKeyFilePaths, string privateKeyF PublicKeys = publicKeys.Select(x => Utilities.ReadPublicKey(x)).ToList(); SecretKey = ReadSecretKey(privateKeyFilePath); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = passPhrase; } public EncryptionKeys(string privateKeyFilePath, string passPhrase) @@ -97,6 +105,7 @@ public EncryptionKeys(string privateKeyFilePath, string passPhrase) PublicKeys = null; SecretKey = ReadSecretKey(privateKeyFilePath); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = passPhrase; } public EncryptionKeys(Stream publicKeyStream, Stream privateKeyStream, string passPhrase) @@ -108,9 +117,10 @@ public EncryptionKeys(Stream publicKeyStream, Stream privateKeyStream, string pa if (passPhrase == null) throw new ArgumentNullException("Invalid Pass Phrase."); - PublicKey = Utilities.ReadPublicKey(publicKeyStream); + PublicKeys = new List() { Utilities.ReadPublicKey(publicKeyStream) }; SecretKey = ReadSecretKey(privateKeyStream); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = passPhrase; } public EncryptionKeys(Stream privateKeyStream, string passPhrase) @@ -120,14 +130,14 @@ public EncryptionKeys(Stream privateKeyStream, string passPhrase) if (passPhrase == null) throw new ArgumentNullException("Invalid Pass Phrase."); - PublicKey = null; SecretKey = ReadSecretKey(privateKeyStream); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = passPhrase; } public EncryptionKeys(IEnumerable publicKeyStreams, Stream privateKeyStream, string passPhrase) { - //Avoid multiple enumerations of 'publicKeyFilePaths' + // Avoid multiple enumerations of 'publicKeyFilePaths' Stream[] publicKeys = publicKeyStreams.ToArray(); if (privateKeyStream == null) @@ -143,23 +153,98 @@ public EncryptionKeys(IEnumerable publicKeyStreams, Stream privateKeyStr PublicKeys = publicKeys.Select(x => Utilities.ReadPublicKey(x)).ToList(); SecretKey = ReadSecretKey(privateKeyStream); PrivateKey = ReadPrivateKey(passPhrase); + _passPhrase = 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 + /// Public key not found. Private key not found. Missing password + public EncryptionKeys(string publicKeyFilePath) + { + if (String.IsNullOrEmpty(publicKeyFilePath)) + throw new ArgumentException("PublicKeyFilePath"); + + if (!File.Exists(publicKeyFilePath)) + throw new FileNotFoundException(String.Format("Public Key file [{0}] does not exist.", publicKeyFilePath)); + + PublicKeys = new List() { Utilities.ReadPublicKey(publicKeyFilePath) }; + } + + /// + /// 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 + /// Public key not found. Private key not found. Missing password + public EncryptionKeys(IEnumerable publicKeyFilePaths) + { + // Avoid multiple enumerations of 'publicKeyFilePaths' + string[] publicKeys = publicKeyFilePaths.ToArray(); + + 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(); + } + + public EncryptionKeys(Stream publicKeyStream) + { + if (publicKeyStream == null) + throw new ArgumentException("PublicKeyStream"); + + PublicKeys = new List() { Utilities.ReadPublicKey(publicKeyStream) }; + } + + public EncryptionKeys(IEnumerable publicKeyStreams) + { + Stream[] publicKeys = publicKeyStreams.ToArray(); + + foreach (Stream publicKey in publicKeys) + { + if (publicKey == null) + throw new ArgumentException("PublicKeyStream"); + } + + PublicKeys = publicKeys.Select(x => Utilities.ReadPublicKey(x)).ToList(); } #endregion Constructors + #region Public Methods + + public PgpPrivateKey FindSecretKey(long keyId) + { + PgpSecretKey pgpSecKey = SecretKeys.GetSecretKey(keyId); + + if (pgpSecKey == null) + return null; + + return pgpSecKey.ExtractPrivateKey(_passPhrase.ToCharArray()); + } + + #endregion Public Methods + #region Secret Key private PgpSecretKey ReadSecretKey(string privateKeyPath) { using (Stream sr = File.OpenRead(privateKeyPath)) + using (Stream inputStream = PgpUtilities.GetDecoderStream(sr)) { - using (Stream inputStream = PgpUtilities.GetDecoderStream(sr)) - { - PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream); - PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle); - if (foundKey != null) - return foundKey; - } + SecretKeys = new PgpSecretKeyRingBundle(inputStream); + PgpSecretKey foundKey = GetFirstSecretKey(SecretKeys); + if (foundKey != null) + return foundKey; } throw new ArgumentException("Can't find signing key in key ring."); } @@ -168,8 +253,8 @@ private PgpSecretKey ReadSecretKey(Stream privateKeyStream) { using (Stream inputStream = PgpUtilities.GetDecoderStream(privateKeyStream)) { - PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream); - PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle); + SecretKeys = new PgpSecretKeyRingBundle(inputStream); + PgpSecretKey foundKey = GetFirstSecretKey(SecretKeys); if (foundKey != null) return foundKey; } diff --git a/PgpCore/IEncryptionKeys.cs b/PgpCore/IEncryptionKeys.cs new file mode 100644 index 0000000..157ae1b --- /dev/null +++ b/PgpCore/IEncryptionKeys.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Org.BouncyCastle.Bcpg.OpenPgp; + +namespace PgpCore +{ + /// + /// Encryption Keys + /// + /// You can supply any or all of these, however, if PrivateKeys + /// are required Secret keys should also be supplied + /// + public interface IEncryptionKeys + { + PgpPublicKey PublicKey { get; } + IEnumerable PublicKeys { get; } + PgpPrivateKey PrivateKey { get; } + PgpSecretKey SecretKey { get; } + PgpSecretKeyRingBundle SecretKeys { get; } + + PgpPrivateKey FindSecretKey(long keyId); + } +} \ No newline at end of file diff --git a/PgpCore/IPGPEncrypt.cs b/PgpCore/IPGPEncrypt.cs new file mode 100644 index 0000000..5e12371 --- /dev/null +++ b/PgpCore/IPGPEncrypt.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace PgpCore +{ + public interface IPGPEncrypt : IDisposable + { + void EncryptFile(string inputFilePath, string outputFilePath, string publicKeyFilePath, bool armor, bool withIntegrityCheck, string name); + + void EncryptFile(string inputFilePath, string outputFilePath, IEnumerable publicKeyFilePaths, bool armor, bool withIntegrityCheck, string name); + + void EncryptStream(Stream inputStream, Stream outputStream, Stream publicKeyStream, bool armor, bool withIntegrityCheck, string name); + + void EncryptStream(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, bool armor, bool withIntegrityCheck, string name); + + void Dispose(); + } +} \ No newline at end of file diff --git a/PgpCore/IPGPEncryptAsync.cs b/PgpCore/IPGPEncryptAsync.cs new file mode 100644 index 0000000..a1cd90e --- /dev/null +++ b/PgpCore/IPGPEncryptAsync.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace PgpCore +{ + public interface IPGPEncryptAsync : IDisposable + { + Task EncryptFileAsync(string inputFilePath, string outputFilePath, string publicKeyFilePath, + bool armor, bool withIntegrityCheck, string name); + + Task EncryptStreamAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, + bool armor, bool withIntegrityCheck, string name); + + Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, + bool armor, bool withIntegrityCheck, string name); + + void Dispose(); + } +} \ No newline at end of file diff --git a/PgpCore/IPGPSign.cs b/PgpCore/IPGPSign.cs new file mode 100644 index 0000000..4a6ed34 --- /dev/null +++ b/PgpCore/IPGPSign.cs @@ -0,0 +1,22 @@ +using System; +using System.IO; + +namespace PgpCore +{ + public interface IPGPSign : IDisposable + { + void SignFile(string inputFilePath, string outputFilePath, + string privateKeyFilePath, string passPhrase, bool armor, bool withIntegrityCheck, string name); + + void SignFile(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, + bool armor, bool withIntegrityCheck, string name); + + void SignStream(Stream inputStream, Stream outputStream, + Stream privateKeyStream, string passPhrase, bool armor, bool withIntegrityCheck, string name); + + void SignStream(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, + bool armor, bool withIntegrityCheck, string name); + + void Dispose(); + } +} \ No newline at end of file diff --git a/PgpCore/IPGPSignAsync.cs b/PgpCore/IPGPSignAsync.cs new file mode 100644 index 0000000..2863686 --- /dev/null +++ b/PgpCore/IPGPSignAsync.cs @@ -0,0 +1,20 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace PgpCore +{ + public interface IPGPSignAsync : IDisposable + { + Task SignFileAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, + bool armor, bool withIntegrityCheck, string name); + + Task SignStreamAsync(Stream inputStream, Stream outputStream, + Stream privateKeyStream, string passPhrase, bool armor, bool withIntegrityCheck, string name); + + Task SignStreamAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, + bool armor, bool withIntegrityCheck, string name); + + void Dispose(); + } +} \ No newline at end of file diff --git a/PgpCore/PGP.cs b/PgpCore/PGP.cs index b59109e..0e051ac 100644 --- a/PgpCore/PGP.cs +++ b/PgpCore/PGP.cs @@ -14,6 +14,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; @@ -21,59 +22,28 @@ namespace PgpCore { public enum PGPFileType { Binary, Text, UTF8 } - public class PGP : IDisposable + public class PGP : IPGPEncrypt, IPGPEncryptAsync, IPGPSign, IPGPSignAsync, IDisposable { public static readonly PGP Instance = new PGP(); private const int BufferSize = 0x10000; private const string DefaultFileName = "name"; - public CompressionAlgorithmTag CompressionAlgorithm - { - get; - set; - } + public CompressionAlgorithmTag CompressionAlgorithm { get; set; } = CompressionAlgorithmTag.Uncompressed; - public SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm - { - get; - set; - } + public SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm { get; set; } = SymmetricKeyAlgorithmTag.TripleDes; - public int PgpSignatureType - { - get; - set; - } + public int PgpSignatureType { get; set; } = PgpSignature.DefaultCertification; - public PublicKeyAlgorithmTag PublicKeyAlgorithm - { - get; - set; - } - public PGPFileType FileType - { - get; - set; - } + public PublicKeyAlgorithmTag PublicKeyAlgorithm { get; set; } = PublicKeyAlgorithmTag.RsaGeneral; - public HashAlgorithmTag HashAlgorithmTag - { - get; - set; - } + public PGPFileType FileType { get; set; } = PGPFileType.Binary; + + public HashAlgorithmTag HashAlgorithmTag { get; set; } = HashAlgorithmTag.Sha1; #region Constructor - public PGP() - { - CompressionAlgorithm = CompressionAlgorithmTag.Uncompressed; - SymmetricKeyAlgorithm = SymmetricKeyAlgorithmTag.TripleDes; - PgpSignatureType = PgpSignature.DefaultCertification; - PublicKeyAlgorithm = PublicKeyAlgorithmTag.RsaGeneral; - FileType = PGPFileType.Binary; - HashAlgorithmTag = HashAlgorithmTag.Sha1; - } + public PGP() { } #endregion Constructor @@ -96,7 +66,27 @@ public async Task EncryptFileAsync( bool withIntegrityCheck = true, string name = DefaultFileName) { - await EncryptFileAsync(inputFilePath, outputFilePath, new[] { publicKeyFilePath }, armor, withIntegrityCheck, name); + await EncryptFileAsync(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePath), armor, withIntegrityCheck, name); + } + + /// + /// PGP Encrypt the file. + /// + /// Plain data file path to be encrypted + /// Output PGP encrypted file path + /// PGP public key file paths + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// True, to perform integrity packet check on input file. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public async Task EncryptFileAsync( + string inputFilePath, + string outputFilePath, + IEnumerable publicKeyFilePaths, + bool armor = true, + bool withIntegrityCheck = true, + string name = DefaultFileName) + { + await EncryptFileAsync(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePaths), armor, withIntegrityCheck, name); } /// @@ -116,7 +106,7 @@ public void EncryptFile( bool withIntegrityCheck = true, string name = DefaultFileName) { - EncryptFile(inputFilePath, outputFilePath, new[] { publicKeyFilePath }, armor, withIntegrityCheck, name); + EncryptFile(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePath), armor, withIntegrityCheck, name); } /// @@ -124,51 +114,28 @@ public void EncryptFile( /// /// Plain data file path to be encrypted /// Output PGP encrypted file path - /// IEnumerable of PGP public key file paths + /// IEncryptionKeys object containing public keys /// True, means a binary data representation as an ASCII-only text. Otherwise, false /// True, to perform integrity packet check on input file. Otherwise, false /// Name of encrypted file in message, defaults to the input file name public async Task EncryptFileAsync( string inputFilePath, string outputFilePath, - IEnumerable publicKeyFilePaths, + IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { - //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 (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - 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)); - } - - List publicKeyStreams = new List(); - - foreach (string publicKeyFilePath in publicKeyFilePaths) - { - MemoryStream memoryStream = new MemoryStream(); - using (Stream publicKeyStream = new FileStream(publicKeyFilePath, FileMode.Open, FileAccess.Read)) - { - await publicKeyStream.CopyToAsync(memoryStream); - memoryStream.Position = 0; - publicKeyStreams.Add(memoryStream); - } - } using (FileStream inputStream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read)) using (Stream outputStream = File.Create(outputFilePath)) - await EncryptStreamAsync(inputStream, outputStream, publicKeyStreams, armor, withIntegrityCheck, name); + await EncryptStreamAsync(inputStream, outputStream, encryptionKeys, armor, withIntegrityCheck, name); } /// @@ -188,39 +155,38 @@ public void EncryptFile( bool withIntegrityCheck = true, string name = DefaultFileName) { - //Avoid multiple enumerations of 'publicKeyFilePaths' - string[] publicKeys = publicKeyFilePaths.ToArray(); + using (FileStream inputStream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read)) + using (Stream outputStream = File.Create(outputFilePath)) + EncryptStream(inputStream, outputStream, new EncryptionKeys(publicKeyFilePaths), armor, withIntegrityCheck, name); + } + /// + /// PGP Encrypt the file. + /// + /// Plain data file path to be encrypted + /// Output PGP encrypted file path + /// IEnumerable of PGP public key file paths + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// True, to perform integrity packet check on input file. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public void EncryptFile( + string inputFilePath, + string outputFilePath, + IEncryptionKeys encryptionKeys, + bool armor = true, + bool withIntegrityCheck = true, + string name = DefaultFileName) + { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - 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)); - } - - List publicKeyStreams = new List(); - - foreach (string publicKeyFilePath in publicKeyFilePaths) - { - MemoryStream memoryStream = new MemoryStream(); - using (Stream publicKeyStream = new FileStream(publicKeyFilePath, FileMode.Open, FileAccess.Read)) - { - publicKeyStream.CopyTo(memoryStream); - memoryStream.Position = 0; - publicKeyStreams.Add(memoryStream); - } - } using (FileStream inputStream = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read)) using (Stream outputStream = File.Create(outputFilePath)) - EncryptStream(inputStream, outputStream, publicKeyStreams, armor, withIntegrityCheck, name); + EncryptStream(inputStream, outputStream, encryptionKeys, armor, withIntegrityCheck, name); } /// @@ -240,7 +206,7 @@ public async Task EncryptStreamAsync( bool withIntegrityCheck = true, string name = DefaultFileName) { - await EncryptStreamAsync(inputStream, outputStream, new[] { publicKeyStream }, armor, withIntegrityCheck, name); + await EncryptStreamAsync(inputStream, outputStream, new EncryptionKeys(publicKeyStream), armor, withIntegrityCheck, name); } /// @@ -260,7 +226,7 @@ public void EncryptStream( bool withIntegrityCheck = true, string name = DefaultFileName) { - EncryptStream(inputStream, outputStream, new[] { publicKeyStream }, armor, withIntegrityCheck, name); + EncryptStream(inputStream, outputStream, new EncryptionKeys(publicKeyStream), armor, withIntegrityCheck, name); } /// @@ -274,18 +240,24 @@ public void EncryptStream( /// Name of encrypted file in message, defaults to the input file name public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { - //Avoid multiple enumerations of 'publicKeyFilePaths' - Stream[] publicKeys = publicKeyStreams.ToArray(); + await EncryptStreamAsync(inputStream, outputStream, new EncryptionKeys(publicKeyStreams), armor, withIntegrityCheck, name); + } + /// + /// PGP Encrypt the stream. + /// + /// Plain data stream to be encrypted + /// Output PGP encrypted stream + /// IEncryptionKeys object containing public keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// True, to perform integrity packet check on input file. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - foreach (Stream publicKey in publicKeys) - { - if (publicKey == null) - throw new ArgumentException("PublicKeyStream"); - } if (name == DefaultFileName && inputStream is FileStream) { @@ -300,9 +272,9 @@ public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IE PgpEncryptedDataGenerator pk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithm, withIntegrityCheck, new SecureRandom()); - foreach (Stream publicKey in publicKeys) + foreach (PgpPublicKey publicKey in encryptionKeys.PublicKeys) { - pk.AddMethod(Utilities.ReadPublicKey(publicKey)); + pk.AddMethod(publicKey); } Stream @out = pk.Open(outputStream, new byte[1 << 16]); @@ -335,18 +307,24 @@ public async Task EncryptStreamAsync(Stream inputStream, Stream outputStream, IE /// Name of encrypted file in message, defaults to the input file name public void EncryptStream(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { - //Avoid multiple enumerations of 'publicKeyFilePaths' - Stream[] publicKeys = publicKeyStreams.ToArray(); + EncryptStream(inputStream, outputStream, new EncryptionKeys(publicKeyStreams), armor, withIntegrityCheck, name); + } + /// + /// PGP Encrypt the stream. + /// + /// Plain data stream to be encrypted + /// Output PGP encrypted stream + /// IEncryptionKeys object containing public keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// True, to perform integrity packet check on input file. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public void EncryptStream(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - foreach (Stream publicKey in publicKeys) - { - if (publicKey == null) - throw new ArgumentException("PublicKeyStream"); - } if (name == DefaultFileName && inputStream is FileStream) { @@ -361,9 +339,9 @@ public void EncryptStream(Stream inputStream, Stream outputStream, IEnumerable publicKeyFilePaths, string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { - //Avoid multiple enumerations of 'publicKeyFilePaths' - string[] publicKeys = publicKeyFilePaths.ToArray(); + await EncryptFileAndSignAsync(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePaths, privateKeyFilePath, passPhrase), armor, withIntegrityCheck, name); + } + /// + /// Encrypt and sign the file pointed to by unencryptedFileInfo and + /// + /// Plain data file path to be encrypted and signed + /// Output PGP encrypted and signed file path + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public async Task EncryptFileAndSignAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - 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)); - } - - EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyFilePaths, privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); if (name == DefaultFileName) { @@ -496,35 +467,28 @@ public async Task EncryptFileAndSignAsync(string inputFilePath, string outputFil public void EncryptFileAndSign(string inputFilePath, string outputFilePath, IEnumerable publicKeyFilePaths, string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { - //Avoid multiple enumerations of 'publicKeyFilePaths' - string[] publicKeys = publicKeyFilePaths.ToArray(); + EncryptFileAndSign(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePaths, privateKeyFilePath, passPhrase), armor, withIntegrityCheck, name); + } + /// + /// Encrypt and sign the file pointed to by unencryptedFileInfo and + /// + /// Plain data file path to be encrypted and signed + /// Output PGP encrypted and signed file path + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public void EncryptFileAndSign(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - 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)); - } - - EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyFilePaths, privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); if (name == DefaultFileName) { @@ -589,27 +553,27 @@ public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, Stream /// Name of encrypted file in message, defaults to the input file name public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + await EncryptStreamAndSignAsync(inputStream, outputStream, new EncryptionKeys(publicKeyStreams, privateKeyStream, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Encrypt and sign the stream pointed to by unencryptedFileInfo and + /// + /// Plain data stream to be encrypted and signed + /// Output PGP encrypted and signed stream + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - 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."); - + if (name == DefaultFileName && inputStream is FileStream) { string inputFilePath = ((FileStream)inputStream).Name; @@ -639,24 +603,24 @@ public async Task EncryptStreamAndSignAsync(Stream inputStream, Stream outputStr /// Name of encrypted file in message, defaults to the input file name public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, IEnumerable publicKeyStreams, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + EncryptStreamAndSign(inputStream, outputStream, new EncryptionKeys(publicKeyStreams, privateKeyStream, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Encrypt and sign the stream pointed to by unencryptedFileInfo and + /// + /// Plain data stream to be encrypted and signed + /// Output PGP encrypted and signed stream + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of encrypted file in message, defaults to the input file name + public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - 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."); @@ -677,7 +641,7 @@ public void EncryptStreamAndSign(Stream inputStream, Stream outputStream, IEnume OutputEncrypted(inputStream, outputStream, encryptionKeys, withIntegrityCheck, name); } - private async Task OutputEncryptedAsync(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private async Task OutputEncryptedAsync(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys, withIntegrityCheck)) { @@ -697,7 +661,7 @@ private async Task OutputEncryptedAsync(string inputFilePath, Stream outputStrea } } - private void OutputEncrypted(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private void OutputEncrypted(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys, withIntegrityCheck)) { @@ -717,7 +681,7 @@ private void OutputEncrypted(string inputFilePath, Stream outputStream, Encrypti } } - private async Task OutputSignedAsync(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private async Task OutputSignedAsync(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { FileInfo unencryptedFileInfo = new FileInfo(inputFilePath); using (Stream compressedOut = ChainCompressedOut(outputStream)) @@ -734,7 +698,7 @@ private async Task OutputSignedAsync(string inputFilePath, Stream outputStream, } } - private void OutputSigned(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private void OutputSigned(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { FileInfo unencryptedFileInfo = new FileInfo(inputFilePath); using (Stream compressedOut = ChainCompressedOut(outputStream)) @@ -751,7 +715,7 @@ private void OutputSigned(string inputFilePath, Stream outputStream, EncryptionK } } - private async Task OutputClearSignedAsync(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys) + private async Task OutputClearSignedAsync(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys) { FileInfo unencryptedFileInfo = new FileInfo(inputFilePath); using (FileStream inputFileStream = unencryptedFileInfo.OpenRead()) @@ -760,7 +724,7 @@ private async Task OutputClearSignedAsync(string inputFilePath, Stream outputStr } } - private void OutputClearSigned(string inputFilePath, Stream outputStream, EncryptionKeys encryptionKeys) + private void OutputClearSigned(string inputFilePath, Stream outputStream, IEncryptionKeys encryptionKeys) { FileInfo unencryptedFileInfo = new FileInfo(inputFilePath); using (FileStream inputFileStream = unencryptedFileInfo.OpenRead()) @@ -769,7 +733,7 @@ private void OutputClearSigned(string inputFilePath, Stream outputStream, Encryp } } - private async Task OutputEncryptedAsync(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private async Task OutputEncryptedAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys, withIntegrityCheck)) { @@ -785,7 +749,7 @@ private async Task OutputEncryptedAsync(Stream inputStream, Stream outputStream, } } - private void OutputEncrypted(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private void OutputEncrypted(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream encryptedOut = ChainEncryptedOut(outputStream, encryptionKeys, withIntegrityCheck)) { @@ -801,7 +765,7 @@ private void OutputEncrypted(Stream inputStream, Stream outputStream, Encryption } } - private async Task OutputSignedAsync(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private async Task OutputSignedAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream compressedOut = ChainCompressedOut(outputStream)) { @@ -814,7 +778,7 @@ private async Task OutputSignedAsync(Stream inputStream, Stream outputStream, En } } - private void OutputSigned(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) + private void OutputSigned(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck, string name) { using (Stream compressedOut = ChainCompressedOut(outputStream)) { @@ -827,7 +791,7 @@ private void OutputSigned(Stream inputStream, Stream outputStream, EncryptionKey } } - private async Task OutputClearSignedAsync(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys) + private async Task OutputClearSignedAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { using (StreamReader streamReader = new StreamReader(inputStream)) using (ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream)) @@ -865,7 +829,7 @@ private async Task OutputClearSignedAsync(Stream inputStream, Stream outputStrea } } - private void OutputClearSigned(Stream inputStream, Stream outputStream, EncryptionKeys encryptionKeys) + private void OutputClearSigned(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { using (StreamReader streamReader = new StreamReader(inputStream)) using (ArmoredOutputStream armoredOutputStream = new ArmoredOutputStream(outputStream)) @@ -951,23 +915,16 @@ private void WriteOutputAndSign(Stream compressedOut, Stream literalOut, Stream signatureGenerator.Generate().Encode(compressedOut); } - private Stream ChainEncryptedOut(Stream outputStream, EncryptionKeys encryptionKeys, bool withIntegrityCheck) + private Stream ChainEncryptedOut(Stream outputStream, IEncryptionKeys encryptionKeys, bool withIntegrityCheck) { PgpEncryptedDataGenerator encryptedDataGenerator; encryptedDataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithm, withIntegrityCheck, new SecureRandom()); - if (encryptionKeys.PublicKey != null) - { - encryptedDataGenerator.AddMethod(encryptionKeys.PublicKey); - } - else if (encryptionKeys.PublicKeys != null) + foreach (PgpPublicKey publicKey in encryptionKeys.PublicKeys) { - foreach (PgpPublicKey publicKey in encryptionKeys.PublicKeys) - { - encryptedDataGenerator.AddMethod(publicKey); - } + encryptedDataGenerator.AddMethod(publicKey); } - + return encryptedDataGenerator.Open(outputStream, new byte[BufferSize]); } @@ -994,7 +951,7 @@ private Stream ChainLiteralStreamOut(Stream compressedOut, Stream inputStream, s return pgpLiteralDataGenerator.Open(compressedOut, FileTypeToChar(), name, inputStream.Length, DateTime.UtcNow); } - private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut, EncryptionKeys encryptionKeys) + private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut, IEncryptionKeys encryptionKeys) { PublicKeyAlgorithmTag tag = encryptionKeys.SecretKey.PublicKey.Algorithm; PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag); @@ -1011,7 +968,7 @@ private PgpSignatureGenerator InitSignatureGenerator(Stream compressedOut, Encry return pgpSignatureGenerator; } - private PgpSignatureGenerator InitClearSignatureGenerator(ArmoredOutputStream armoredOutputStream, EncryptionKeys encryptionKeys) + private PgpSignatureGenerator InitClearSignatureGenerator(ArmoredOutputStream armoredOutputStream, IEncryptionKeys encryptionKeys) { PublicKeyAlgorithmTag tag = encryptionKeys.SecretKey.PublicKey.Algorithm; PgpSignatureGenerator pgpSignatureGenerator = new PgpSignatureGenerator(tag, HashAlgorithmTag); @@ -1043,25 +1000,30 @@ private PgpSignatureGenerator InitClearSignatureGenerator(ArmoredOutputStream ar /// Name of signed file in message, defaults to the input file name public async Task SignFileAsync(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + await SignFileAsync(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Sign the file pointed to by unencryptedFileInfo and + /// + /// Plain data file path to be signed + /// Output PGP signed file path + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of signed file in message, defaults to the input file name + public async Task SignFileAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, + bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); if (name == DefaultFileName) { @@ -1093,25 +1055,30 @@ public async Task SignFileAsync(string inputFilePath, string outputFilePath, /// Name of signed file in message, defaults to the input file name public void SignFile(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + SignFile(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Sign the file pointed to by unencryptedFileInfo and + /// + /// Plain data file path to be signed + /// Output PGP signed file path + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of signed file in message, defaults to the input file name + public void SignFile(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys, + bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); if (name == DefaultFileName) { @@ -1143,18 +1110,25 @@ public void SignFile(string inputFilePath, string outputFilePath, /// Name of signed file in message, defaults to the input file name public async Task SignStreamAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + await SignStreamAsync(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Sign the stream pointed to by unencryptedFileInfo and + /// + /// Plain data stream to be signed + /// Output PGP signed stream + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of signed file in message, defaults to the input file name + public async Task SignStreamAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, + bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyStream, passPhrase); - if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -1186,18 +1160,25 @@ public async Task SignStreamAsync(Stream inputStream, Stream outputStream, /// Name of signed file in message, defaults to the input file name public void SignStream(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) + { + SignStream(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase), armor, withIntegrityCheck, name); + } + + /// + /// Sign the stream pointed to by unencryptedFileInfo and + /// + /// Plain data stream to be signed + /// Output PGP signed stream + /// Encryption keys + /// True, means a binary data representation as an ASCII-only text. Otherwise, false + /// Name of signed file in message, defaults to the input file name + public void SignStream(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys, + bool armor = true, bool withIntegrityCheck = true, string name = DefaultFileName) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyStream, passPhrase); - if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -1231,25 +1212,27 @@ public void SignStream(Stream inputStream, Stream outputStream, /// PGP secret key file path /// PGP secret key password public async Task ClearSignFileAsync(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase) + { + await ClearSignFileAsync(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase)); + } + + /// + /// Clear sign the file pointed to by unencryptedFileInfo + /// + /// Plain data file path to be signed + /// Output PGP signed file path + /// Encryption keys + public async Task ClearSignFileAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); using (Stream outputStream = File.Create(outputFilePath)) { @@ -1265,25 +1248,27 @@ public async Task ClearSignFileAsync(string inputFilePath, string outputFilePath /// PGP secret key file path /// PGP secret key password public void ClearSignFile(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase) + { + ClearSignFile(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase)); + } + + /// + /// Clear sign the file pointed to by unencryptedFileInfo + /// + /// Plain data file path to be signed + /// Output PGP signed file path + /// Encryption keys + public void ClearSignFile(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Input file [{0}] does not exist.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key file [{0}] does not exist.", privateKeyFilePath)); - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyFilePath, passPhrase); - - if (encryptionKeys == null) - throw new ArgumentNullException("Encryption Key not found."); using (Stream outputStream = File.Create(outputFilePath)) { @@ -1299,18 +1284,22 @@ public void ClearSignFile(string inputFilePath, string outputFilePath, string pr /// PGP secret key stream /// PGP secret key password public async Task ClearSignStreamAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + { + await ClearSignStreamAsync(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase)); + } + + /// + /// Clear sign the provided stream + /// + /// Plain data stream to be signed + /// Output PGP signed stream + /// Encryption keys + public async Task ClearSignStreamAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyStream, passPhrase); - if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -1325,18 +1314,22 @@ public async Task ClearSignStreamAsync(Stream inputStream, Stream outputStream, /// PGP secret key stream /// PGP secret key password public void ClearSignStream(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + { + ClearSignStream(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase)); + } + + /// + /// Clear sign the provided stream + /// + /// Plain data stream to be signed + /// Output PGP signed stream + /// Encryption keys + public void ClearSignStream(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - EncryptionKeys encryptionKeys = new EncryptionKeys(privateKeyStream, passPhrase); - if (encryptionKeys == null) throw new ArgumentNullException("Encryption Key not found."); @@ -1355,29 +1348,31 @@ public void ClearSignStream(Stream inputStream, Stream outputStream, Stream priv /// PGP secret key file path /// PGP secret key password public async Task DecryptFileAsync(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase) + { + await DecryptFileAsync(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase)); + } + + /// + /// PGP decrypt a given file. + /// + /// PGP encrypted data file path + /// Output PGP decrypted file path + /// Encryption keys + public async Task DecryptFileAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - { - using (Stream keyStream = File.OpenRead(privateKeyFilePath)) - { - using (Stream outStream = File.Create(outputFilePath)) - await DecryptAsync(inputStream, outStream, keyStream, passPhrase); - } - } + using (Stream outStream = File.Create(outputFilePath)) + await DecryptStreamAsync(inputStream, outStream, encryptionKeys); } /// @@ -1388,29 +1383,31 @@ public async Task DecryptFileAsync(string inputFilePath, string outputFilePath, /// PGP secret key file path /// PGP secret key password public void DecryptFile(string inputFilePath, string outputFilePath, string privateKeyFilePath, string passPhrase) + { + DecryptFile(inputFilePath, outputFilePath, new EncryptionKeys(privateKeyFilePath, passPhrase)); + } + + /// + /// PGP decrypt a given file. + /// + /// PGP encrypted data file path + /// Output PGP decrypted file path + /// Encryption keys + public void DecryptFile(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); if (String.IsNullOrEmpty(outputFilePath)) throw new ArgumentException("OutputFilePath"); - if (String.IsNullOrEmpty(privateKeyFilePath)) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - { - using (Stream keyStream = File.OpenRead(privateKeyFilePath)) - { - using (Stream outStream = File.Create(outputFilePath)) - Decrypt(inputStream, outStream, keyStream, passPhrase); - } - } + using (Stream outStream = File.Create(outputFilePath)) + Decrypt(inputStream, outStream, encryptionKeys); } /// @@ -1421,17 +1418,27 @@ public void DecryptFile(string inputFilePath, string outputFilePath, string priv /// PGP secret key stream /// PGP secret key password public async Task DecryptStreamAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + { + await DecryptStreamAsync(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase)); + return outputStream; + } + + /// + /// PGP decrypt a given stream. + /// + /// PGP encrypted data stream + /// Output PGP decrypted stream + /// Encryption keys + public async Task DecryptStreamAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - await DecryptAsync(inputStream, outputStream, privateKeyStream, passPhrase); + await DecryptAsync(inputStream, outputStream, encryptionKeys); return outputStream; } @@ -1443,37 +1450,45 @@ public async Task DecryptStreamAsync(Stream inputStream, Stream outputSt /// PGP secret key stream /// PGP secret key password public Stream DecryptStream(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + { + DecryptStream(inputStream, outputStream, new EncryptionKeys(privateKeyStream, passPhrase)); + return outputStream; + } + + /// + /// PGP decrypt a given stream. + /// + /// PGP encrypted data stream + /// Output PGP decrypted stream + /// Encryption keys + public Stream DecryptStream(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyFilePath"); - if (passPhrase == null) - passPhrase = String.Empty; + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - Decrypt(inputStream, outputStream, privateKeyStream, passPhrase); + Decrypt(inputStream, outputStream, encryptionKeys); return outputStream; } - /* - * PGP decrypt a given stream. - */ - private async Task DecryptAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + /// + /// PGP decrypt a given stream. + /// + /// PGP encrypted data stream + /// Output PGP decrypted stream + /// Encryption keys + /// + private async Task DecryptAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("outputStream"); - if (privateKeyStream == null) - throw new ArgumentException("privateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; PgpObjectFactory objFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream)); - // find secret key - PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); PgpObject obj = null; if (objFactory != null) @@ -1491,7 +1506,7 @@ private async Task DecryptAsync(Stream inputStream, Stream outputStream, Stream PgpPublicKeyEncryptedData pbe = null; foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects()) { - privateKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray()); + privateKey = encryptionKeys.FindSecretKey(pked.KeyId); if (privateKey != null) { @@ -1566,23 +1581,21 @@ private async Task DecryptAsync(Stream inputStream, Stream outputStream, Stream throw new PgpException("Message is not a simple encrypted file."); } - /* - * PGP decrypt a given stream. - */ - private void Decrypt(Stream inputStream, Stream outputStream, Stream privateKeyStream, string passPhrase) + /// + /// PGP decrypt a given stream. + /// + /// PGP encrypted data stream + /// Output PGP decrypted stream + /// Encryption keys + /// + private void Decrypt(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("outputStream"); - if (privateKeyStream == null) - throw new ArgumentException("privateKeyStream"); - if (passPhrase == null) - passPhrase = String.Empty; PgpObjectFactory objFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream)); - // find secret key - PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); PgpObject obj = null; if (objFactory != null) @@ -1604,7 +1617,7 @@ private void Decrypt(Stream inputStream, Stream outputStream, Stream privateKeyS PgpPublicKeyEncryptedData pbe = null; foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects()) { - privateKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray()); + privateKey = encryptionKeys.FindSecretKey(pked.KeyId); if (privateKey != null) { @@ -1692,32 +1705,29 @@ private void Decrypt(Stream inputStream, Stream outputStream, Stream privateKeyS /// PGP secret key file path /// PGP secret key password public async Task DecryptFileAndVerifyAsync(string inputFilePath, string outputFilePath, string publicKeyFilePath, string privateKeyFilePath, string passPhrase) + { + await DecryptFileAndVerifyAsync(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePath, privateKeyFilePath, passPhrase)); + } + + /// + /// PGP decrypt and verify a given file. + /// + /// PGP encrypted data file path to be decrypted and verified + /// Output PGP decrypted and verified file path + /// Encryption keys + public async Task DecryptFileAndVerifyAsync(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { 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) - passPhrase = String.Empty; if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - { - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - using (Stream privateKeyStream = File.OpenRead(privateKeyFilePath)) - using (Stream outStream = File.Create(outputFilePath)) - await DecryptAndVerifyAsync(inputStream, outStream, publicKeyStream, privateKeyStream, passPhrase); - } + using (Stream outStream = File.Create(outputFilePath)) + await DecryptStreamAndVerifyAsync(inputStream, outStream, encryptionKeys); } /// @@ -1729,32 +1739,29 @@ public async Task DecryptFileAndVerifyAsync(string inputFilePath, string outputF /// PGP secret key file path /// PGP secret key password public void DecryptFileAndVerify(string inputFilePath, string outputFilePath, string publicKeyFilePath, string privateKeyFilePath, string passPhrase) + { + DecryptFileAndVerify(inputFilePath, outputFilePath, new EncryptionKeys(publicKeyFilePath, privateKeyFilePath, passPhrase)); + } + + /// + /// PGP decrypt and verify a given file. + /// + /// PGP encrypted data file path to be decrypted and verified + /// Output PGP decrypted and verified file path + /// Encryption keys + public void DecryptFileAndVerify(string inputFilePath, string outputFilePath, IEncryptionKeys encryptionKeys) { 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) - passPhrase = String.Empty; if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); - if (!File.Exists(privateKeyFilePath)) - throw new FileNotFoundException(String.Format("Private Key File [{0}] not found.", privateKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - { - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - using (Stream privateKeyStream = File.OpenRead(privateKeyFilePath)) - using (Stream outStream = File.Create(outputFilePath)) - DecryptAndVerify(inputStream, outStream, publicKeyStream, privateKeyStream, passPhrase); - } + using (Stream outStream = File.Create(outputFilePath)) + DecryptAndVerify(inputStream, outStream, encryptionKeys); } /// @@ -1766,19 +1773,27 @@ public void DecryptFileAndVerify(string inputFilePath, string outputFilePath, st /// PGP secret key stream /// PGP secret key password public async Task DecryptStreamAndVerifyAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase) + { + await DecryptStreamAndVerifyAsync(inputStream, outputStream, new EncryptionKeys(publicKeyStream, privateKeyStream, passPhrase)); + return outputStream; + } + + /// + /// PGP decrypt and verify a given stream. + /// + /// PGP encrypted data stream to be decrypted and verified + /// Output PGP decrypted and verified stream + /// IEncryptionKeys object containing public key, private key and passphrase + public async Task DecryptStreamAndVerifyAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyFileStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyFileStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - await DecryptAndVerifyAsync(inputStream, outputStream, publicKeyStream, privateKeyStream, passPhrase); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); + + await DecryptAndVerifyAsync(inputStream, outputStream, encryptionKeys); return outputStream; } @@ -1791,29 +1806,36 @@ public async Task DecryptStreamAndVerifyAsync(Stream inputStream, Stream /// PGP secret key stream /// PGP secret key password public Stream DecryptStreamAndVerify(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase) + { + DecryptStreamAndVerify(inputStream, outputStream, new EncryptionKeys(publicKeyStream, privateKeyStream, passPhrase)); + return outputStream; + } + + /// + /// PGP decrypt and verify a given stream. + /// + /// PGP encrypted data stream to be decrypted and verified + /// Output PGP decrypted and verified stream + /// Encryption keys + public Stream DecryptStreamAndVerify(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); if (outputStream == null) throw new ArgumentException("OutputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyFileStream"); - if (privateKeyStream == null) - throw new ArgumentException("PrivateKeyFileStream"); - if (passPhrase == null) - passPhrase = String.Empty; - - DecryptAndVerify(inputStream, outputStream, publicKeyStream, privateKeyStream, passPhrase); + + DecryptAndVerify(inputStream, outputStream, encryptionKeys); return outputStream; } - /* - * PGP decrypt and verify a given stream. - */ - private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase) + /// + /// PGP decrypt and verify a given stream. + /// + /// PGP encrypted data stream to be decrypted and verified + /// Output PGP decrypted and verified stream + /// Encryption keys + private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { - // find secret key - PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); PgpEncryptedDataList encryptedDataList = Utilities.GetEncryptedDataList(PgpUtilities.GetDecoderStream(inputStream)); // decrypt @@ -1821,7 +1843,7 @@ private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream PgpPublicKeyEncryptedData pbe = null; foreach (PgpPublicKeyEncryptedData pked in encryptedDataList.GetEncryptedDataObjects()) { - privateKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray()); + privateKey = encryptionKeys.FindSecretKey(pked.KeyId); if (privateKey != null) { @@ -1833,8 +1855,6 @@ private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream if (privateKey == null) throw new ArgumentException("Secret key for message not found."); - var publicKey = Utilities.ReadPublicKey(publicKeyStream); - PgpObjectFactory plainFact = null; using (Stream clear = pbe.GetDataStream(privateKey)) { @@ -1857,7 +1877,7 @@ private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream { PgpOnePassSignature pgpOnePassSignature = pgpOnePassSignatureList[0]; - var verified = publicKey.KeyId == pgpOnePassSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId); + var verified = encryptionKeys.PublicKey.KeyId == pgpOnePassSignature.KeyId || encryptionKeys.PublicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId); if (verified == false) throw new PgpException("Failed to verify file."); @@ -1883,13 +1903,14 @@ private async Task DecryptAndVerifyAsync(Stream inputStream, Stream outputStream throw new PgpException("Message is not a simple encrypted file."); } - /* - * PGP decrypt and verify a given stream. - */ - private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase) + /// + /// PGP decrypt and verify a given stream. + /// + /// PGP encrypted data stream to be decrypted and verified + /// Output PGP decrypted and verified stream + /// Encryption keys + private void DecryptAndVerify(Stream inputStream, Stream outputStream, IEncryptionKeys encryptionKeys) { - // find secret key - PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream)); PgpEncryptedDataList encryptedDataList = Utilities.GetEncryptedDataList(PgpUtilities.GetDecoderStream(inputStream)); // decrypt @@ -1897,7 +1918,7 @@ private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream pu PgpPublicKeyEncryptedData pbe = null; foreach (PgpPublicKeyEncryptedData pked in encryptedDataList.GetEncryptedDataObjects()) { - privateKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray()); + privateKey = encryptionKeys.FindSecretKey(pked.KeyId); if (privateKey != null) { @@ -1909,8 +1930,6 @@ private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream pu if (privateKey == null) throw new ArgumentException("Secret key for message not found."); - var publicKey = Utilities.ReadPublicKey(publicKeyStream); - PgpObjectFactory plainFact = null; using (Stream clear = pbe.GetDataStream(privateKey)) { @@ -1933,7 +1952,7 @@ private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream pu { PgpOnePassSignature pgpOnePassSignature = pgpOnePassSignatureList[0]; - var verified = publicKey.KeyId == pgpOnePassSignature.KeyId || publicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId); + var verified = encryptionKeys.PublicKey.KeyId == pgpOnePassSignature.KeyId || encryptionKeys.PublicKey.GetKeySignatures().Cast().Select(x => x.KeyId).Contains(pgpOnePassSignature.KeyId); if (verified == false) throw new PgpException("Failed to verify file."); @@ -1965,20 +1984,25 @@ private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream pu /// Plain data file path to be verified /// PGP public key file path public async Task VerifyFileAsync(string inputFilePath, string publicKeyFilePath) + { + return await VerifyFileAsync(inputFilePath, new EncryptionKeys(publicKeyFilePath)); + } + + /// + /// PGP verify a given file. + /// + /// Plain data file path to be verified + /// IEncryptionKeys object containing public keys + public async Task VerifyFileAsync(string inputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); - if (String.IsNullOrEmpty(publicKeyFilePath)) - throw new ArgumentException("PublicKeyFilePath"); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - return await VerifyAsync(inputStream, publicKeyStream); + return await VerifyAsync(inputStream, encryptionKeys); } /// @@ -1987,20 +2011,25 @@ public async Task VerifyFileAsync(string inputFilePath, string publicKeyFi /// Plain data file path to be verified /// PGP public key file path public bool VerifyFile(string inputFilePath, string publicKeyFilePath) + { + return VerifyFile(inputFilePath, new EncryptionKeys(publicKeyFilePath)); + } + + /// + /// PGP verify a given file. + /// + /// Plain data file path to be verified + /// Encryption keys + public bool VerifyFile(string inputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); - if (String.IsNullOrEmpty(publicKeyFilePath)) - throw new ArgumentException("PublicKeyFilePath"); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - return Verify(inputStream, publicKeyStream); + return Verify(inputStream, encryptionKeys); } /// @@ -2009,20 +2038,24 @@ public bool VerifyFile(string inputFilePath, string publicKeyFilePath) /// Plain data file path to be verified /// PGP public key file path public async Task VerifyClearFileAsync(string inputFilePath, string publicKeyFilePath) + { + return await VerifyClearFileAsync(inputFilePath, new EncryptionKeys(publicKeyFilePath)); + } + + /// + /// PGP verify a given clear signed file. + /// + /// Plain data file path to be verified + /// Encryption keys + public async Task VerifyClearFileAsync(string inputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); - if (String.IsNullOrEmpty(publicKeyFilePath)) - throw new ArgumentException("PublicKeyFilePath"); - - if (!File.Exists(inputFilePath)) - throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); using (Stream inputStream = File.OpenRead(inputFilePath)) - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - return await VerifyClearAsync(inputStream, publicKeyStream); + return await VerifyClearAsync(inputStream, encryptionKeys); } /// @@ -2031,20 +2064,27 @@ public async Task VerifyClearFileAsync(string inputFilePath, string public /// Plain data file path to be verified /// PGP public key file path public bool VerifyClearFile(string inputFilePath, string publicKeyFilePath) + { + return VerifyClearFile(inputFilePath, new EncryptionKeys(publicKeyFilePath)); + } + + /// + /// PGP verify a given clear signed file. + /// + /// Plain data file path to be verified + /// Encryption keys + public bool VerifyClearFile(string inputFilePath, IEncryptionKeys encryptionKeys) { if (String.IsNullOrEmpty(inputFilePath)) throw new ArgumentException("InputFilePath"); - if (String.IsNullOrEmpty(publicKeyFilePath)) - throw new ArgumentException("PublicKeyFilePath"); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); if (!File.Exists(inputFilePath)) throw new FileNotFoundException(String.Format("Encrypted File [{0}] not found.", inputFilePath)); - if (!File.Exists(publicKeyFilePath)) - throw new FileNotFoundException(String.Format("Public Key File [{0}] not found.", publicKeyFilePath)); using (Stream inputStream = File.OpenRead(inputFilePath)) - using (Stream publicKeyStream = File.OpenRead(publicKeyFilePath)) - return VerifyClear(inputStream, publicKeyStream); + return VerifyClear(inputStream, encryptionKeys); } /// @@ -2053,13 +2093,23 @@ public bool VerifyClearFile(string inputFilePath, string publicKeyFilePath) /// Plain data stream to be verified /// PGP public key stream public async Task VerifyStreamAsync(Stream inputStream, Stream publicKeyStream) + { + return await VerifyStreamAsync(inputStream, new EncryptionKeys(publicKeyStream)); + } + + /// + /// PGP verify a given stream. + /// + /// Plain data stream to be verified + /// Encryption keys + public async Task VerifyStreamAsync(Stream inputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - return await VerifyAsync(inputStream, publicKeyStream); + return await VerifyAsync(inputStream, encryptionKeys); } /// @@ -2068,13 +2118,23 @@ public async Task VerifyStreamAsync(Stream inputStream, Stream publicKeySt /// Plain data stream to be verified /// PGP public key stream public bool VerifyStream(Stream inputStream, Stream publicKeyStream) + { + return Verify(inputStream, new EncryptionKeys(publicKeyStream)); + } + + /// + /// PGP verify a given stream. + /// + /// Plain data stream to be verified + /// Encryption keys + public bool VerifyStream(Stream inputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - return Verify(inputStream, publicKeyStream); + return Verify(inputStream, encryptionKeys); } /// @@ -2083,33 +2143,54 @@ public bool VerifyStream(Stream inputStream, Stream publicKeyStream) /// Clear signed data stream to be verified /// PGP public key stream public async Task VerifyClearStreamAsync(Stream inputStream, Stream publicKeyStream) + { + return await VerifyClearStreamAsync(inputStream, new EncryptionKeys(publicKeyStream)); + } + + /// + /// PGP verify a given clear signed stream. + /// + /// Clear signed data stream to be verified + /// Encryption keys + public async Task VerifyClearStreamAsync(Stream inputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - return await VerifyClearAsync(inputStream, publicKeyStream); + return await VerifyClearAsync(inputStream, encryptionKeys); } + /// /// PGP verify a given clear signed stream. /// /// Clear signed stream to be verified /// PGP public key stream public bool VerifyClearStream(Stream inputStream, Stream publicKeyStream) + { + return VerifyClearStream(inputStream, new EncryptionKeys(publicKeyStream)); + } + + /// + /// PGP verify a given clear signed stream. + /// + /// Clear signed stream to be verified + /// Encryption keys + public bool VerifyClearStream(Stream inputStream, IEncryptionKeys encryptionKeys) { if (inputStream == null) throw new ArgumentException("InputStream"); - if (publicKeyStream == null) - throw new ArgumentException("PublicKeyStream"); + if (encryptionKeys == null) + throw new ArgumentNullException("Encryption Key not found."); - return VerifyClear(inputStream, publicKeyStream); + return VerifyClear(inputStream, encryptionKeys); } - private async Task VerifyAsync(Stream inputStream, Stream publicKeyStream) + private async Task VerifyAsync(Stream inputStream, IEncryptionKeys encryptionKeys) { - PgpPublicKey publicKey = Utilities.ReadPublicKey(publicKeyStream); + PgpPublicKey publicKey = encryptionKeys.PublicKey; bool verified = false; System.IO.Stream encodedFile = PgpUtilities.GetDecoderStream(inputStream); @@ -2166,9 +2247,9 @@ private async Task VerifyAsync(Stream inputStream, Stream publicKeyStream) return verified; } - private bool Verify(Stream inputStream, Stream publicKeyStream) + private bool Verify(Stream inputStream, IEncryptionKeys encryptionKeys) { - PgpPublicKey publicKey = Utilities.ReadPublicKey(publicKeyStream); + PgpPublicKey publicKey = encryptionKeys.PublicKey; bool verified = false; ArmoredInputStream encodedFile = new ArmoredInputStream(inputStream); @@ -2226,13 +2307,13 @@ private bool Verify(Stream inputStream, Stream publicKeyStream) } // https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs - private async Task VerifyClearAsync(Stream inputStream, Stream publicKeyStream) + private async Task VerifyClearAsync(Stream inputStream, IEncryptionKeys encryptionKeys) { bool verified = false; using (MemoryStream outStream = new MemoryStream()) { - var publicKey = Utilities.ReadPublicKey(publicKeyStream); + var publicKey = encryptionKeys.PublicKey; PgpSignature pgpSignature; using (ArmoredInputStream armoredInputStream = new ArmoredInputStream(inputStream)) @@ -2298,13 +2379,13 @@ private async Task VerifyClearAsync(Stream inputStream, Stream publicKeySt } // https://github.com/bcgit/bc-csharp/blob/master/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs - private bool VerifyClear(Stream inputStream, Stream publicKeyStream) + private bool VerifyClear(Stream inputStream, IEncryptionKeys encryptionKeys) { bool verified = false; using (MemoryStream outStream = new MemoryStream()) { - var publicKey = Utilities.ReadPublicKey(publicKeyStream); + var publicKey = encryptionKeys.PublicKey; PgpSignature pgpSignature; using (ArmoredInputStream armoredInputStream = new ArmoredInputStream(inputStream)) diff --git a/PgpCore/PgpCore.csproj b/PgpCore/PgpCore.csproj index 6581f40..00fe141 100644 --- a/PgpCore/PgpCore.csproj +++ b/PgpCore/PgpCore.csproj @@ -1,8 +1,8 @@  - netstandard2.1;netcoreapp2.2;netcoreapp3.1 - .NET Standard and Core class library for using PGP + netstandard2.0 + .NET Standard class library for using PGP mattosaurus PgpCore diff --git a/PgpCore/Utilities.cs b/PgpCore/Utilities.cs index 24e90ba..ea4b790 100644 --- a/PgpCore/Utilities.cs +++ b/PgpCore/Utilities.cs @@ -89,6 +89,12 @@ public static string GetSignatureName( case PublicKeyAlgorithmTag.Dsa: encAlg = "DSA"; break; + case PublicKeyAlgorithmTag.ECDH: + encAlg = "ECDH"; + break; + case PublicKeyAlgorithmTag.ECDsa: + encAlg = "ECDSA"; + break; case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases. case PublicKeyAlgorithmTag.ElGamalGeneral: encAlg = "ElGamal"; @@ -101,7 +107,7 @@ public static string GetSignatureName( } public static string GetSymmetricCipherName( - SymmetricKeyAlgorithmTag algorithm) + SymmetricKeyAlgorithmTag algorithm) { switch (algorithm) { @@ -127,6 +133,12 @@ public static string GetSymmetricCipherName( return "AES"; case SymmetricKeyAlgorithmTag.Twofish: return "Twofish"; + case SymmetricKeyAlgorithmTag.Camellia128: + return "Camellia"; + case SymmetricKeyAlgorithmTag.Camellia192: + return "Camellia"; + case SymmetricKeyAlgorithmTag.Camellia256: + return "Camellia"; default: throw new PgpException("unknown symmetric algorithm: " + algorithm); } @@ -145,14 +157,17 @@ public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm) case SymmetricKeyAlgorithmTag.Blowfish: case SymmetricKeyAlgorithmTag.Safer: case SymmetricKeyAlgorithmTag.Aes128: + case SymmetricKeyAlgorithmTag.Camellia128: keySize = 128; break; case SymmetricKeyAlgorithmTag.TripleDes: case SymmetricKeyAlgorithmTag.Aes192: + case SymmetricKeyAlgorithmTag.Camellia192: keySize = 192; break; case SymmetricKeyAlgorithmTag.Aes256: case SymmetricKeyAlgorithmTag.Twofish: + case SymmetricKeyAlgorithmTag.Camellia256: keySize = 256; break; default: diff --git a/README.md b/README.md index 7df03a8..4b33e58 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ # PgpCore + +[![CircleCI](https://circleci.com/gh/mattosaurus/pgpcore/tree/master.svg?style=svg)]() + A .NET Core class library for using PGP. -This is based on ChoPGP but updated to .NET Core framework and to add in a missing utilities class. +This is based on ChoPGP but updated to .NET Standard and to add in a missing utilities class. # Installation To use PgpCore in your C# project, you can either download the PgpCore C# .NET libraries directly from the Github repository or, if you have the NuGet package manager installed, you can grab them automatically. @@ -17,12 +20,10 @@ Add the following namespaces to use the library: using PgpCore; ``` # Dependencies -BouncyCastle.NetCore (>= 1.8.1.3) - -Microsoft.NETCore.App (>= 1.1.2) +* Portable.BouncyCastle (>= 1.8.6.7) # Usage -This is intended for usage in .NET Core projects, the latest version that works with .NET Framework is v2.2.0. +This is intended for usage in projects [targeting .NET Standard 2.0](https://dotnet.microsoft.com/platform/dotnet-standard#versions). ## Methods