Skip to content

Commit

Permalink
Add verify methods
Browse files Browse the repository at this point in the history
  • Loading branch information
mattosaurus committed May 5, 2019
1 parent c22d933 commit 8857c98
Show file tree
Hide file tree
Showing 3 changed files with 324 additions and 0 deletions.
236 changes: 236 additions & 0 deletions PgpCore/PGP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,242 @@ private void Decrypt(Stream inputStream, Stream outputStream, Stream privateKeyS

#endregion Decrypt

#region DecryptAndVerify

public async Task DecryptFileAndVerifyAsync(string inputFilePath, string outputFilePath, string publicKeyFilePath, string privateKeyFilePath, string passPhrase)
{
await Task.Run(() => DecryptFileAndVerify(inputFilePath, outputFilePath, publicKeyFilePath, privateKeyFilePath, passPhrase));
}

public async Task DecryptStreamAndAndVerifyAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase)
{
await Task.Run(() => DecryptStreamAndVerify(inputStream, outputStream, publicKeyStream, privateKeyStream, passPhrase));
}

public async Task VerifyFileAsync(string inputFilePath, string publicKeyFilePath)
{
await Task.Run(() => VerifyFile(inputFilePath, publicKeyFilePath));
}

public async Task VerifyStreamAsync(Stream inputStream, Stream publicKeyStream)
{
await Task.Run(() => VerifyStream(inputStream, publicKeyStream));
}

/// <summary>
/// PGP decrypt and verify a given file.
/// </summary>
/// <param name="inputFilePath"></param>
/// <param name="outputFilePath"></param>
/// <param name="publicKeyFilePath"></param>
/// <param name="privateKeyFilePath"></param>
/// <param name="passPhrase"></param>
public void DecryptFileAndVerify(string inputFilePath, string outputFilePath, string publicKeyFilePath, string privateKeyFilePath, string passPhrase)
{
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);
}
}

/// <summary>
/// PGP decrypt and verify a given stream.
/// </summary>
/// <param name="inputStream"></param>
/// <param name="outputStream"></param>
/// <param name="privateKeyFilePath"></param>
/// <param name="passPhrase"></param>
public Stream DecryptStreamAndVerify(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase)
{
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);
return outputStream;
}

/*
* PGP decrypt and verify a given stream.
*/
private void DecryptAndVerify(Stream inputStream, Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase)
{
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKeyStream, privateKeyStream, passPhrase);
PgpPublicKeyEncryptedData publicKeyED = Utilities.ExtractPublicKeyEncryptedData(inputStream);

if (publicKeyED.KeyId != encryptionKeys.PublicKey.KeyId)
throw new PgpException(String.Format("Failed to verify file."));

PgpObject message = Utilities.GetClearCompressedMessage(publicKeyED, encryptionKeys);

PgpObjectFactory objFactory = new PgpObjectFactory(PgpUtilities.GetDecoderStream(inputStream));
// find secret key
PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(PgpUtilities.GetDecoderStream(privateKeyStream));

PgpObject obj = null;
if (objFactory != null)
obj = objFactory.NextPgpObject();

// the first object might be a PGP marker packet.
PgpEncryptedDataList enc = null;
if (obj is PgpEncryptedDataList)
enc = (PgpEncryptedDataList)obj;
else
enc = (PgpEncryptedDataList)objFactory.NextPgpObject();

// decrypt
PgpPrivateKey privateKey = null;
PgpPublicKeyEncryptedData pbe = null;
foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
{
privateKey = FindSecretKey(pgpSec, pked.KeyId, passPhrase.ToCharArray());

if (privateKey != null)
{
pbe = pked;
break;
}
}

if (privateKey == null)
throw new ArgumentException("Secret key for message not found.");

PgpObjectFactory plainFact = null;

using (Stream clear = pbe.GetDataStream(privateKey))
{
plainFact = new PgpObjectFactory(clear);
}

if (message is PgpCompressedData)
{
PgpCompressedData cData = (PgpCompressedData)message;
PgpObjectFactory of = null;

using (Stream compDataIn = cData.GetDataStream())
{
of = new PgpObjectFactory(compDataIn);
}

message = of.NextPgpObject();
if (message is PgpOnePassSignatureList)
{
message = of.NextPgpObject();
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, outputStream);
}
else
{
PgpLiteralData Ld = null;
Ld = (PgpLiteralData)message;
Stream unc = Ld.GetInputStream();
Streams.PipeAll(unc, outputStream);
}
}
else if (message is PgpLiteralData)
{
PgpLiteralData ld = (PgpLiteralData)message;
string outFileName = ld.FileName;

Stream unc = ld.GetInputStream();
Streams.PipeAll(unc, outputStream);

if (pbe.IsIntegrityProtected())
{
if (!pbe.Verify())
{
throw new PgpException("Message failed integrity check.");
}
}
}
else
throw new PgpException("Message is not a simple encrypted file.");
}

/// <summary>
/// PGP verify a given file.
/// </summary>
/// <param name="inputFilePath"></param>
/// <param name="publicKeyFilePath"></param>
public bool VerifyFile(string inputFilePath, string publicKeyFilePath)
{
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);
}

/// <summary>
/// PGP verify a given stream.
/// </summary>
/// <param name="inputStream"></param>
/// <param name="publicKeyStream"></param>
public bool VerifyStream(Stream inputStream, Stream publicKeyStream)
{
if (inputStream == null)
throw new ArgumentException("InputStream");
if (publicKeyStream == null)
throw new ArgumentException("PublicKeyStream");

return Verify(inputStream, publicKeyStream);
}

public bool Verify(Stream inputStream, Stream publicKeyStream)
{
PgpPublicKeyEncryptedData publicKeyED = Utilities.ExtractPublicKeyEncryptedData(inputStream);
PgpPublicKey publicKey = Utilities.ReadPublicKey(publicKeyStream);

if (publicKeyED.KeyId == publicKey.KeyId)
{
return true;
}
else
{
return false;
}
}

#endregion DecryptAndVerify

#region GenerateKey

public async Task GenerateKeyAsync(string publicKeyFilePath, string privateKeyFilePath, string username = null, string password = null, int strength = 1024, int certainty = 8)
Expand Down
13 changes: 13 additions & 0 deletions PgpCore/Properties/PublishProfiles/FolderProfile.pubxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netstandard1.3</TargetFramework>
<PublishDir>bin\Release\netstandard1.3\publish\</PublishDir>
</PropertyGroup>
</Project>
75 changes: 75 additions & 0 deletions PgpCore/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -505,5 +505,80 @@ public static Stream GetDecoderStream(
return new ArmoredInputStream(inputStream, hasHeaders);
}
}

public static PgpPublicKeyEncryptedData ExtractPublicKeyEncryptedData(System.IO.Stream inputStream)
{
System.IO.Stream encodedFile = PgpUtilities.GetDecoderStream(inputStream);
PgpEncryptedDataList encryptedDataList = GetEncryptedDataList(encodedFile);
PgpPublicKeyEncryptedData publicKeyED = ExtractPublicKey(encryptedDataList);
return publicKeyED;
}

public static PgpObject ProcessCompressedMessage(PgpObject message)
{
PgpCompressedData compressedData = (PgpCompressedData)message;
Stream compressedDataStream = compressedData.GetDataStream();
PgpObjectFactory compressedFactory = new PgpObjectFactory(compressedDataStream);
message = CheckforOnePassSignatureList(message, compressedFactory);
return message;
}

public static PgpObject CheckforOnePassSignatureList(PgpObject message, PgpObjectFactory compressedFactory)
{
message = compressedFactory.NextPgpObject();
if (message is PgpOnePassSignatureList)
{
message = compressedFactory.NextPgpObject();
}
return message;
}

internal static PgpObject GetClearCompressedMessage(PgpPublicKeyEncryptedData publicKeyED, EncryptionKeys encryptionKeys)
{
PgpObjectFactory clearFactory = GetClearDataStream(encryptionKeys.PrivateKey, publicKeyED);
PgpObject message = clearFactory.NextPgpObject();
if (message is PgpOnePassSignatureList)
message = clearFactory.NextPgpObject();
return message;
}

public static PgpObjectFactory GetClearDataStream(PgpPrivateKey privateKey, PgpPublicKeyEncryptedData publicKeyED)
{
Stream clearStream = publicKeyED.GetDataStream(privateKey);
PgpObjectFactory clearFactory = new PgpObjectFactory(clearStream);
return clearFactory;
}

public static PgpPublicKeyEncryptedData ExtractPublicKey(PgpEncryptedDataList encryptedDataList)
{
PgpPublicKeyEncryptedData publicKeyED = null;
foreach (PgpPublicKeyEncryptedData privateKeyED in encryptedDataList.GetEncryptedDataObjects())
{
if (privateKeyED != null)
{
publicKeyED = privateKeyED;
break;
}
}
return publicKeyED;
}

public static PgpEncryptedDataList GetEncryptedDataList(Stream encodedFile)
{
PgpObjectFactory factory = new PgpObjectFactory(encodedFile);
PgpObject pgpObject = factory.NextPgpObject();

PgpEncryptedDataList encryptedDataList;

if (pgpObject is PgpEncryptedDataList)
{
encryptedDataList = (PgpEncryptedDataList)pgpObject;
}
else
{
encryptedDataList = (PgpEncryptedDataList)factory.NextPgpObject();
}
return encryptedDataList;
}
}
}

0 comments on commit 8857c98

Please sign in to comment.