using Org.BouncyCastle.Bcpg; using Org.BouncyCastle.Bcpg.OpenPgp; using Org.BouncyCastle.Security; using System; using System.IO; using System.Text; using Org.BouncyCastle.Utilities.IO; namespace LCU.Api.Internal.FileOperations.Services { public static class CryptoHelper { private static PgpPublicKey ReadPublicKey(Stream inputStream) { inputStream = PgpUtilities.GetDecoderStream(inputStream); PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream); foreach (PgpPublicKeyRing keyRing in pgpPub.GetKeyRings()) { foreach (PgpPublicKey key in keyRing.GetPublicKeys()) { if (key.IsEncryptionKey) { return key; } } } throw new ArgumentException("Can't find encryption key in key ring."); } private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyId, char[] pass) { PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId); return pgpSecKey?.ExtractPrivateKey(pass); } public static void DecryptPgpFile(string inputFile, string outputFile, string keyFile, string passPhrase) { var encryptedFileData = File.ReadAllBytes(inputFile); var secretKeyData = File.ReadAllBytes(keyFile); var decryptedData = DecryptPgpData(encryptedFileData, secretKeyData, passPhrase); File.WriteAllText(outputFile, decryptedData); } public static string DecryptPgpData(byte[] inputData, byte[] secretKeyData, string passPhrase) { Stream inputStream = new MemoryStream(inputData); Stream secretKeyStream = new MemoryStream(secretKeyData); string output; PgpObjectFactory pgpFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream)); // find secret key PgpSecretKeyRingBundle pgpKeyRing = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(secretKeyStream)); PgpObject pgp = null; if (pgpFactory != null) { pgp = pgpFactory.NextPgpObject(); } // the first object might be a PGP marker packet. PgpEncryptedDataList encryptedData = null; if (pgp is PgpEncryptedDataList) { encryptedData = (PgpEncryptedDataList)pgp; } else { encryptedData = (PgpEncryptedDataList)pgpFactory.NextPgpObject(); } // decrypt PgpPrivateKey privateKey = null; PgpPublicKeyEncryptedData pubKeyData = null; foreach (PgpPublicKeyEncryptedData pubKeyDataItem in encryptedData.GetEncryptedDataObjects()) { privateKey = FindSecretKey(pgpKeyRing, pubKeyDataItem.KeyId, passPhrase.ToCharArray()); if (privateKey != null) { pubKeyData = pubKeyDataItem; break; } } if (privateKey == null) { throw new ArgumentException("Secret key for message not found."); } PgpObjectFactory plainFact = null; using (Stream clear = pubKeyData.GetDataStream(privateKey)) { plainFact = new PgpObjectFactory(clear); } PgpObject message = plainFact.NextPgpObject(); switch (message) { case PgpCompressedData data: { PgpCompressedData compressedData = data; PgpObjectFactory pgpCompressedFactory = null; using (Stream compDataIn = compressedData.GetDataStream()) { pgpCompressedFactory = new PgpObjectFactory(compDataIn); } message = pgpCompressedFactory.NextPgpObject(); PgpLiteralData literalData = null; if (message is PgpOnePassSignatureList) { message = pgpCompressedFactory.NextPgpObject(); } literalData = (PgpLiteralData)message; using (Stream unc = literalData.GetInputStream()) { output = GetString(unc); } break; } case PgpLiteralData data: { PgpLiteralData literalData = data; using (Stream unc = literalData.GetInputStream()) { output = GetString(unc); } break; } case PgpOnePassSignatureList _: throw new PgpException("Encrypted message contains a signed message - not literal data."); default: throw new PgpException("Message is not a simple encrypted file - type unknown."); } return output; } public static void EncryptPgpFile(string inputFile, string outputFile, string publicKeyFile, bool applyArmor, bool withIntegrityCheck) { using (Stream publicKeyStream = File.OpenRead(publicKeyFile)) { PgpPublicKey pubKey = ReadPublicKey(publicKeyStream); using (MemoryStream outputBytes = new MemoryStream()) { PgpCompressedDataGenerator dataCompressor = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip); PgpUtilities.WriteFileToLiteralData(dataCompressor.Open(outputBytes), PgpLiteralData.Binary, new FileInfo(inputFile)); dataCompressor.Close(); PgpEncryptedDataGenerator dataGenerator = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom()); dataGenerator.AddMethod(pubKey); byte[] dataBytes = outputBytes.ToArray(); using (Stream outputStream = File.Create(outputFile)) { if (applyArmor) { using (ArmoredOutputStream armoredStream = new ArmoredOutputStream(outputStream)) { WriteStream(dataGenerator.Open(armoredStream, dataBytes.Length), ref dataBytes); } } else { WriteStream(dataGenerator.Open(outputStream, dataBytes.Length), ref dataBytes); } } } } } public static void WriteStream(Stream inputStream, ref byte[] dataBytes) { using (Stream outputStream = inputStream) { outputStream.Write(dataBytes, 0, dataBytes.Length); } } public static string GetString(Stream inputStream) { string output; using (StreamReader reader = new StreamReader(inputStream)) { output = reader.ReadToEnd(); } return output; } public static Stream GetStream(string stringData) { MemoryStream stream = new MemoryStream(); StreamWriter writer = new StreamWriter(stream); writer.Write(stringData); writer.Flush(); stream.Position = 0; return stream; } } }