Files
monorepo/LCU.API.Internal.FileOperations/LCU.Api.Internal.FileOperations/Services/CryptoHelper.cs
T
2026-04-27 10:50:07 -05:00

213 lines
7.7 KiB
C#

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;
}
}
}