213 lines
7.7 KiB
C#
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;
|
|
}
|
|
}
|
|
} |