Code Monkey home page Code Monkey logo

pgpcore's Introduction

PgpCore

.NET

A .NET Core class library for using PGP.

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 download it from NuGet.

Once you have the PgpCore libraries properly referenced in your project, you can include calls to them in your code.

Add the following namespaces to use the library:

using PgpCore;

Dependencies

  • Portable.BouncyCastle (>= 1.9.0)

Usage

This is intended for usage in projects targeting .NET Standard 2.0.

Azure Function Example

If you want a (basic) example of how you can use an Azure Function to encrypt/decrypt from Azure Blob Storage I've created a sample project here.

Methods

Settings

Generate Key

Generate a new public and private key for the provided username and password.

gpg --gen-key

GenerateKey

using (PGP pgp = new PGP())
{
	// Generate keys
	pgp.GenerateKey(new FileInfo(@"C:\TEMP\Keys\public.asc"), new FileInfo(@"C:\TEMP\Keys\private.asc"), "[email protected]", "password");
}

Inspect

Inspect the provided file, stream or string and return a PGPInspectResult object that contains details on the messages encryption and sign status as well as additional information on filename, headers, etc. where available.

gpg --list-packets "C:\TEMP\Content\encrypted.pgp"

Inspect File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

// Reference input file
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\encrypted.pgp");

// Inspect
PGP pgp = new PGP();
PgpInspectResult result = await pgp.InspectAsync(inputFile);

Inspect Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream, privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input stream
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encrypted.pgp", FileMode.Open))
	// Inspect
	PgpInspectResult result = await pgp.InspectAsync(inputFileStream);

Inspect String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
string privatyeKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

// Inspect
PGP pgp = new PGP(encryptionKeys);
PgpInspectResult result = await pgp.InspectAsync("String to inspect");

Encrypt

Encrypt the provided file, stream or string using a public key.

Optional headers can be provided to include in the encrypted file. These can be set by providing a Dictionary<string, string> to the headers parameter. The key of the dictionary will be the header name and the value will be the header value.

gpg --output "C:\TEMP\Content\encrypted.pgp" --encrypt "C:\TEMP\Content\content.txt"

Encrypt File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\content.txt");
FileInfo encryptedFile = new FileInfo(@"C:\TEMP\Content\encrypted.pgp");

// Encrypt
PGP pgp = new PGP(encryptionKeys);
await pgp.EncryptAsync(inputFile, encryptedFile);

Encrypt Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream);

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\encrypted.pgp"))
	// Encrypt
	await pgp.EncryptAsync(inputFileStream, outputFileStream);

Encrypt String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Encrypt
PGP pgp = new PGP(encryptionKeys);
string encryptedContent = await pgp.EncryptAsync("String to encrypt");

Sign

Sign the provided file or stream using a private key.

Optional headers can be provided to include in the signed file. These can be set by providing a Dictionary<string, string> to the headers parameter. The key of the dictionary will be the header name and the value will be the header value.

gpg --output "C:\TEMP\Content\content.txt" --sign "C:\TEMP\Content\signed.pgp"

Sign File

// Load keys
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\content.txt");
FileInfo signedFile = new FileInfo(@"C:\TEMP\Content\signed.pgp");

// Sign
PGP pgp = new PGP(encryptionKeys);
await pgp.SignAsync(inputFile, signedFile);

Sign Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\signed.pgp"))
	// Sign
	await pgp.SignAsync(inputFileStream, outputFileStream);

Sign String

// Load keys
string privateKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

PGP pgp = new PGP(encryptionKeys);

// Sign
string signedContent = await pgp.SignAsync("String to sign");

Clear Sign

Clear sign the provided file, stream, or string using a private key so that it is still human readable. A common use of digital signatures is to sign usenet postings or email messages. In such situations it is undesirable to compress the document while signing it. This is because the signature would then depend on the compression algorithm used. This is problematic when different people use different compression algorithms. To overcome this problem, the OpenPGP digital signature format has a special type of signature that is not computed on the message itself. Instead, the signature is computed on a "cleartext" version of the message - a version that is exactly the same as the original message except that it is not compressed and certain types of information (such as the end of line markers) are not included. This cleartext version is then compressed and the signature is appended to the compressed cleartext to produce the final message.

gpg --output "C:\TEMP\Content\content.txt" --clearsign "C:\TEMP\Content\clearSigned.pgp"

Clear Sign File

// Load keys
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\content.txt");
FileInfo signedFile = new FileInfo(@"C:\TEMP\Content\signed.pgp");

// Sign
PGP pgp = new PGP(encryptionKeys);
await pgp.ClearSignAsync(inputFile, signedFile);

Clear Sign Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\signed.pgp"))
	// Sign
	await pgp.ClearSignAsync(inputFileStream, outputFileStream);

Clear Sign String

// Load keys
string privateKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

PGP pgp = new PGP(encryptionKeys);

// Sign
string signedContent = await pgp.ClearSignAsync("String to sign");

Encrypt and Sign

Encrypt the provided file, stream or string using a public key and sign using your private key. You usually encrypt with the public key of your counterparty so they can decrypt with their private key and sign with your private key so they can verify with your public key.

Although this method is called EncryptAndSign the signature will actually be included within the encrypted message rather than being appended to the encrypted message. This ensures that the original message was composed by the holder of the private key.

gpg --encrypt --sign --recipient 'some user ID value' "C:\TEMP\keys\content.txt"

Encrypt File And Sign

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\content.txt");
FileInfo encryptedSignedFile = new FileInfo(@"C:\TEMP\Content\encryptedSigned.pgp");

// Encrypt and Sign
PGP pgp = new PGP(encryptionKeys);
await pgp.EncryptAndSignAsync(inputFile, encryptedSignedFile);

Encrypt Stream And Sign

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream, privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\content.txt", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\signed.pgp"))
	// Encrypt and Sign
	await pgp.EncryptAndSignAsync(inputFileStream, outputFileStream);

Encrypt String And Sign

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
string privateKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

PGP pgp = new PGP(encryptionKeys);

// Encrypt and Sign
string encryptedSignedContent = await pgp.EncryptAndSignAsync("String to encrypt and sign");

Decrypt

Decrypt the provided file, stream or string using the matching private key and passphrase.

gpg --output "C:\TEMP\Content\decrypted.txt" --decrypt "C:\TEMP\Content\encrypted.pgp"

Decrypt File

// Load keys
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\encryptedContent.pgp");
FileInfo decryptedFile = new FileInfo(@"C:\TEMP\Content\decrypted.txt");

// Decrypt
PGP pgp = new PGP(encryptionKeys);
await pgp.DecryptAsync(inputFile, decryptedFile);

Decrypt Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedContent.pgp", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\decrypted.txt"))
	// Decrypt
	await pgp.DecryptAsync(inputFileStream, outputFileStream);

Decrypt String

// Load keys
string privateKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(privateKey, "password");

PGP pgp = new PGP(encryptionKeys);

// Decrypt
string decryptedContent = await pgp.DecryptAsync("String to decrypt");

Verify

Verify that the file, stream or string was signed by the matching private key of the counterparty.

gpg --verify "C:\TEMP\Content\signed.pgp"

Verify File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Reference input
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\signedContent.pgp");

// Verify
PGP pgp = new PGP(encryptionKeys);
bool verified = await pgp.VerifyAsync(inputFile);

Verify Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream);

PGP pgp = new PGP(encryptionKeys);

// Reference input file
bool verified;
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedContent.pgp", FileMode.Open))
	// Verify
	verified = await pgp.VerifyAsync(inputFileStream);

Verify String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

PGP pgp = new PGP(encryptionKeys);

// Verify
bool verified = await pgp.VerifyAsync("String to verify");

Verify and Read

Verify that the file, stream was signed by the matching private key of the counterparty. This is an overload of the Verify method that takes an additional output argument. Please note that this is not available for the string based method.

Verify And Read File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Reference input
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\signedContent.pgp");
FileInfo outputFile = new FileInfo(@"C:\TEMP\Content\decryptedContent.txt");

// Verify and read
PGP pgp = new PGP(encryptionKeys);
bool verified = await pgp.VerifyAsync(inputFile, outputFile);

Verify And Read Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream);

PGP pgp = new PGP(encryptionKeys);

// Reference input file
bool verified;
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedContent.pgp", FileMode.Open))
using (FileStream outputFileStream = new FileStream(@"C:\TEMP\Content\decryptedContent.pgp", FileMode.Open))
	// Verify and read
	verified = await pgp.VerifyAsync(inputFileStream);

Verify And Read String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

PGP pgp = new PGP(encryptionKeys);

// Verify and read
string output = string.Empty;
bool verified = await pgp.VerifyAsync("String to verify", output);

Verify Clear

Verify that the clear signed file or stream was signed by the matching private key of the counterparty.

gpg --verify "C:\TEMP\Content\clearSigned.pgp"

Verify Clear File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Reference input
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\signedContent.pgp");

// Verify
PGP pgp = new PGP(encryptionKeys);
bool verified = await pgp.VerifyClearAsync(inputFile);

Verify Clear Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
	encryptionKeys = new EncryptionKeys(publicKeyStream);

PGP pgp = new PGP(encryptionKeys);

// Reference input file
bool verified;
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedContent.pgp", FileMode.Open))
	// Verify
	verified = await pgp.VerifyClearAsync(inputFileStream);

Verify Clear String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

PGP pgp = new PGP(encryptionKeys);

// Verify
bool verified = await pgp.VerifyClearAsync("String to verify");

Verify and Read Clear

Verify that the clear signed file or stream was signed by the matching private key of the counterparty. This is an overload of the VerifyClear method that takes an additional output argument.

Verify And Read Clear File

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

// Reference input
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\signedContent.pgp");
FileInfo outputFile = new FileInfo(@"C:\TEMP\Content\decryptedContent.txt");

// Verify and read
PGP pgp = new PGP(encryptionKeys);
bool verified = await pgp.VerifyClearAsync(inputFile, outputFile);

Verify And Read Clear Stream

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
    encryptionKeys = new EncryptionKeys(publicKeyStream);

PGP pgp = new PGP(encryptionKeys);

// Reference input file
bool verified;
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedContent.pgp", FileMode.Open))
using (FileStream outputFileStream = new FileStream(@"C:\TEMP\Content\decryptedContent.pgp", FileMode.Open))
    // Verify and read
    verified = await pgp.VerifyClearAsync(inputFileStream);

Verify And Read Clear String

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey);

PGP pgp = new PGP(encryptionKeys);

// Verify and read
string output = string.Empty;
bool verified = await pgp.VerifyClearAsync("String to verify", output);

Decrypt and Verify

Decrypt and then verify the provided encrypted and signed file, stream or string. Usually your counterparty will encrypt with your public key and sign with their private key so you can decrypt with your private key and verify with their public key.

The DecryptAndVerify methods will only work with files that have been encrypted and signed using the EncryptAndSign methods. This is because the signature is included within the encrypted message rather than being appended to the encrypted message. If a file is first encrypted using an Encrypt method and then signed using a Sign method then the signature will be appended to the encrypted message rather than embedded within it and the DecryptAndVerify methods will not be able to verify the signature.

gpg --output "C:\TEMP\Content\encryptedAndSigned.pgp" --decrypt "C:\TEMP\Content\decryptedAndVerified.txt"

Decrypt File And Verify

// Load keys
FileInfo publicKey = new FileInfo(@"C:\TEMP\Keys\public.asc");
FileInfo privateKey = new FileInfo(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

// Reference input/output files
FileInfo inputFile = new FileInfo(@"C:\TEMP\Content\encryptedSigned.pgp");
FileInfo outputFile = new FileInfo(@"C:\TEMP\Content\content.txt");

// Decrypt and Verify
PGP pgp = new PGP(encryptionKeys);
await pgp.DecryptAndVerifyAsync(inputFile, outputFile);

Decrypt Stream And Verify

// Load keys
EncryptionKeys encryptionKeys;
using (Stream publicKeyStream = new FileStream(@"C:\TEMP\Keys\public.asc", FileMode.Open))
using (Stream privateKeyStream = new FileStream(@"C:\TEMP\Keys\private.asc", FileMode.Open))
    encryptionKeys = new EncryptionKeys(publicKeyStream, privateKeyStream, "password");

PGP pgp = new PGP(encryptionKeys);

// Reference input/output files
using (FileStream inputFileStream = new FileStream(@"C:\TEMP\Content\encryptedSigned.pgp", FileMode.Open))
using (Stream outputFileStream = File.Create(@"C:\TEMP\Content\content.txtp"))
    // Decrypt and Verify
    await pgp.DecryptAndVerifyAsync(inputFileStream, outputFileStream);

Decrypt String And Verify

// Load keys
string publicKey = File.ReadAllText(@"C:\TEMP\Keys\public.asc");
string privateKey = File.ReadAllText(@"C:\TEMP\Keys\private.asc");
EncryptionKeys encryptionKeys = new EncryptionKeys(publicKey, privateKey, "password");

PGP pgp = new PGP(encryptionKeys);

// Decrypt and Verify
string encryptedSignedContent = await pgp.DecryptAndVerifyAsync("String to decrypt and verify");

Settings

The PGP object contains a variety of settings properties that can be used to determine how files are encrypted.

CompressionAlgorithm

The compression algorithim to be used on the message. This is applied prior to encryption, either to the message or the signed message.

  • Uncompressed - Default
  • Zip
  • ZLib
  • BZip2

SymmetricKeyAlgorithm

The private key encryption algorithm.

Although TripleDes is the default, it is outdated and being discouraged by security institutions like NIST. Aes is recommended.

  • Null
  • Idea
  • TripleDes - Default
  • Cast5
  • Blowfish
  • Safer
  • Des
  • Aes128
  • Aes192
  • Aes256
  • Twofish
  • Camellia128
  • Camellia192
  • Camellia256

PgpSignatureType

The type of signature to be used for file signing.

  • BinaryDocument
  • CanonicalTextDocument
  • StandAlone
  • DefaultCertification - Default
  • NoCertification
  • CasualCertification
  • PositiveCertification
  • SubkeyBinding
  • PrimaryKeyBinding
  • DirectKey
  • KeyRevocation
  • SubkeyRevocation
  • CertificationRevocation
  • Timestamp

PublicKeyAlgorithm

The public key encryption algorithim.

  • RsaGeneral - Default
  • RsaEncrypt
  • RsaSign
  • ElGamalEncrypt
  • Dsa
  • ECDH
  • ECDsa
  • ElGamalGeneral
  • DiffieHellman
  • EdDsa

FileType

Encoding to be used for the output file.

  • Binary - Default
  • Text
  • UTF8

HashAlgorithmTag

The hash algorithim to be used by the signature.

  • MD5
  • Sha1 - Default
  • RipeMD160
  • DoubleSha
  • MD2
  • Tiger192
  • Haval5pass160
  • Sha256
  • Sha384
  • Sha512
  • Sha224

pgpcore's People

Contributors

0xced avatar anderssteennilsen avatar bitcoinbrisbane avatar bizouarn avatar blackboxlogic avatar cravecode avatar dennisholmer avatar felix-exon avatar gtbuchanan avatar hazelrah-qr avatar hippish avatar james-lappin avatar james-lappin-cko avatar jernik avatar jtone123 avatar lfalck avatar liam-rougoor avatar mattosaurus avatar mrvandalid avatar pnc-matthewgrant avatar ptrstpp950 avatar pugacha avatar robvangeloven avatar rodneyrichardson avatar sebkuru avatar skumarspace avatar srasp avatar tilicon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pgpcore's Issues

Base64 encode encrypted stream

I have a method that encrypts a Stream:
public async Task<Stream> EncryptAsync(Stream streamToEncrypt, string publicKey) { using var pgp = new PGP(); Stream outputStream = new MemoryStream(); using (streamToEncrypt) using (var publicKeyStream = publicKey.ConvertToStream()) { await pgp.EncryptStreamAsync(streamToEncrypt, outputStream, publicKeyStream, true, true); outputStream.Seek(0, SeekOrigin.Begin); return outputStream; } }

It is being used by a web endpoint so encoding the encrypted data is likely the best way to reduce formatting issues etc. (e.g. Base64). What is a good way to encode the encrypted Stream without hitting the constraints of multiple Byte[] copies and MemoryStream size constraints?

Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing found where PgpSecretKeyRing expected

HI I am facing error Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing found where PgpSecretKeyRing expected.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PgpCore;
using System.IO;
using System.Text;

namespace TEC_CitiEncryption
{
public class Class1
{
static void Main(string[] args)
{
using (PGP pgp = new PGP())
{

            String search_file = @"C:\UAT Testing\file.txt"; 
            String outputFile_file = @"C:\UAT Testing\Notfile.pgp"; 
            String password = "1AS5D32eafsd5f3alasdkjf39ldk339j7yid9";
            String public_File = @"C:\Users\syaphkg5axInstall\Documents\PGP Key Ankur\DLIP-PROD.asc";
            String private_File = @"C:\Users\syaphkg5axInstall\Documents\PGP Key Ankur\DAN India IT AX TEAM.asc";

            // Encrypt and sign file
            pgp.EncryptFileAndSign(search_file, outputFile_file,public_File, private_File, password, true, true);
            }
        }
}

}

I am sure that I am passing the correct keys.

Make Properly Async

Make async methods properly async rather than just wrapping synchronous actions.

GPG Compatibility

Hi,

First of all, great job on the library, it certainly takes the pain out of using the BouncyCastle APIs directly.

It looks like others have run into this issue but it seems that I can't sign and verify (+ encrypt/decrypt variants) when using keys generated using gpg. I am however able to encrypt and decrypt without signing/verifying.

I'm using the gpg command line tool and

gpg --generate-key 

To generate the key pairs. Then the following commands to export the keys so I can use them in my test app:

gpg --export -a --openpgp [email protected] > test_pub.asc 
gpg --export-secret-key -a --openpgp [email protected] > test.asc

I figured it may be a compatibility issue with PGP hence the --openpgp flag but this doesn't seem to make a difference.

Keys generated with https://pgpkeygen.com/ do work as expected.

Also, on a different topic, would you be open to a PR that makes the library truly async as currently the sync calls are just being wrapped in a Task.Run?

How to verify signed stream

Hi, i can sign the stream

using (var inputStream = new MemoryStream(messageToSign))
                using (var outputStream = new MemoryStream())
                using (Stream privateKeyStream = new FileStream(privateKey, FileMode.Open, FileAccess.Read))
                using (PGP pgp = new PGP())
                {
                    await pgp.SignStreamAsync(inputStream, outputStream, privateKeyStream, pass);
                    return signature.ToArray();
                }

but i cannot verify even with original message that it was signed.

i found out only

            using (var inputStream = new MemoryStream(signature))
            using (Stream publicKeyStream = new FileStream(publicKey, FileMode.Open, FileAccess.Read))
            using (PGP pgp = new PGP())
            {
                return pgp.VerifyStreamAsync(inputStream,  publicKeyStream);
            }

the problem is that in this i only verify that signature is signed with that public key, and not that the original message (messageToSign) is signed in that signature..

what is the best practice to verify the signed message?

SignFile resulting structure is unexpected/ wrong

I'm using the following code for signing a file:

using PgpCore;
using System;
using System.IO;

namespace GpgTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Begin");

            string basePath = "";
            string fileBare = Path.Combine(basePath, @"testData\content.txt");
            string fileEncrypted = Path.Combine(basePath, @"testData\content.txt.encrypt.pgp");
            string fileSigned = Path.Combine(basePath, @"testData\content.txt.signed.pgp");

            Directory.CreateDirectory("keys");
            Directory.CreateDirectory("testData");
            File.WriteAllText(fileBare, "MyTestContent");
            using (PGP pgp = new PGP())
            {
                string KeyPub = Path.Combine(basePath, @"keys\public.asc");
                string KeyPriv = Path.Combine(basePath, @"keys\private.asc");
                string KeyPasswd = @"password";
                // Generate keys
                pgp.GenerateKey(KeyPub, KeyPriv, "[email protected]", KeyPasswd);
                
                pgp.SignFile(fileBare, fileSigned, KeyPriv, KeyPasswd, true, true);
            }

            Console.WriteLine("Done");
        }
    }
}

This produces a file with the following contents:

-----BEGIN PGP MESSAGE-----
Version: BCPG C# v1.8.5.0

kA0DAAIBR2nEQUeYkD4Byx5iC2NvbnRlbnQudHh0XZNmFE15VGVzdENvbnRlbnSI
rwQAAQIAGQUCXZNJ9BIcZW1haWxAZXhhbXBsZS5jb20ACgkQR2nEQUeYkD4+JgP/
abO2vPjGj03J9AZe1OenyPdm/l+qN3xh++no8lqTW2t/KInhE8bnQyo2bNXLB+l0
FWt3AQRfMQYPRZ2wn6jcC+MolYc9dTQYbccsjv1nEeLOi5IbJ+i/Lk7h1B0EV2xU
xGXKNUGrs26eFVeFdLFkuZfnaHT+TVV1W3vYmpUPO6I=
=KIlz
-----END PGP MESSAGE-----

I would expect a file like the following (Signature/ Structure taken from http://apt.postgresql.org/pub/repos/apt/dists/bionic-pgdg/InRelease):

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

MyTestContent
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEEuXsK/KoaR/BE8kSgf8x9RqzMTPgFAl2Mt24ACgkQf8x9RqzM
TPiFhw/8DM18ObaqnkX50G/T05EF4fTvbbfDIjSpHOP6eNCThC+FViuL74gcfSTv
FW2JtozWHo9Bm4V2AnoNCYSdc3cXIMcq8DVtaSY/ccR4s3CT6yo5oDKZT7/l5fkK
RJLlQuQdJzUKHEAzGx0jZQqY/E/jtNqS+BvIYlpPjwk3BLEzW4jqf5Lokf8eEgM5
ffnRE1plf8I8ciDcrUWsaQKGCPDAMFraqriT7pkB7y3rjrP77oFtU3VsZBUc2JS5
29A9/6fTLIGwSjcbXksQ88FXzENvE+MqIR4zojGLrg/vOlU08FjUuZUkAAhdQ0G6
PLlOBhn90JypFTfADfaGKK4DzUX1xOhQhbNNwXTDimkwjLYJb0waeen8vI0F4nnh
4I75fmBC4/mLLL0WnOYV3f12bFuZrA77+ispeUfsE24ZYiG68sVri7P1IWfAtMoZ
TaIWKblUZ2ZLOb223qEJNVvGGxuiJe3hXeifsFG4m/b9IPdiU8ZMe5knLbjNz3Sg
Plax2VVyESWA4kkol7TwhsjkfN1Mj4g5hrD6VckQ4M8UaXr2EvxpbjnIWMGrW7WM
fCOwiBfqiH9GMvTLpbgy/frMbMr/7Oc/4EOVLzHfid5yNd74aE5Z8rPUQhjNm1ah
j38FiIajeGq9/sFc9Xs2L6CNotaPNo3F0XcJpQLAXEPHwbID23k=
=GYF1
-----END PGP SIGNATURE-----

Looking at the ArmoredOutputStream from the underlying library, it is capable to create files with that structure:
https://github.com/bcgit/bc-csharp/blob/7248688e6f513cbdde1ccc1d39904cb964b0c88a/crypto/src/bcpg/ArmoredOutputStream.cs#L196

DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);

https://github.com/bcgit/bc-csharp/blob/7248688e6f513cbdde1ccc1d39904cb964b0c88a/crypto/src/bcpg/ArmoredOutputStream.cs#L258-260

case PacketTag.Signature:
  type = "SIGNATURE";
  break;

Even if the current verison of the library should only save the signature (I do not get it from the function itself), this file should begin with "BEGIN PGP SIGNATURE" instead of "BEGIN PGP MESSAGE". But as the file is always larger than the encrypted one, I would suspect, that the content signature are inside the file.

Strong Name

Have you thought about following Microsoft's guidance on providing strong-named assemblies for libraries? For some, strong-named libraries are required (e.g. COM objects), and StrongNamer does not work perfectly or in all scenarios. FYI, Portable.BouncyCastle is strong-named.

A tip to help those that strong-names causes issues: your AssemblyVersion does not have to change for each release. All 2.x.x.x releases can have AssemblyVersion 2.0.0.0, etc.

โœ”๏ธ CONSIDER strong naming your library's assemblies.

โœ”๏ธ CONSIDER adding the strong naming key to your source control system.

โœ”๏ธ CONSIDER incrementing the assembly version on only major version changes to help users reduce binding redirects, and how often they're updated.

https://docs.microsoft.com/en-us/dotnet/standard/library-guidance/strong-naming

Issue with decrypting binary files

Decryption fails with error when I try to decrypt a file that has binary contents instead of the normal -----BEGIN PGP MESSAGE----- text file. I have checked the private key and public key are correct, also tried to decrypt it with openpgp js module with binary option and it worked there. But doesn't work with PgpCore, kindly help me out, I am using this in Azure function. See code below. Thanks.

        public virtual async Task Decrypt(Client client, Stream blobStream, CloudBlobStream decryptedStream, ILogger log)
        {
            try
            {
                using (PGP pgp = new PGP())
                {
                    Stream privateKeyStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(client.PgpConfig.PrivateKey));
                    log.LogInformation($"::::::x {pgp.FileType.ToString()}"); // this prints binary for all files
                    await DecryptStreamAsync(pgp, blobStream, decryptedStream, privateKeyStream, client.PgpConfig.Passphrase);
                    await decryptedStream.CommitAsync();
                }
            } 
            catch (Exception ex)
            {
                log.LogError($"Error while decrypting file {ex.Message} {ex.StackTrace}");
                exception = ex;
            }
        }
       
         public virtual async Task DecryptStreamAsync(PGP pgp, Stream stream, CloudBlobStream decryptedStream, Stream privateKeyStream, string passphrase)
        {
            await pgp.DecryptStreamAsync(stream, decryptedStream, privateKeyStream, passphrase);
        }

Error while decrypting file unknown object in stream Reserved at Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.NextPgpObject() in D:\a\1\s\crypto\src\openpgp\PgpObjectFactory.cs:line 119 at Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.AllPgpObjects() in D:\a\1\s\crypto\src\openpgp\PgpObjectFactory.cs:line 136 at PgpCore.PGP.DecryptAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, String passPhrase) at PgpCore.PGP.DecryptStreamAsync(Stream inputStream, Stream outputStream, Stream privateKeyStream, String passPhrase) at SofyImportV3.common.PgpDecrypter.DecryptStreamAsync(PGP pgp, Stream stream, CloudBlobStream decryptedStream, Stream privateKeyStream, String passphrase) in /Users/kamesh/Desktop/Sofy/SofyUnit/azure_functions/SofyImportV3/common/PGPDecrypter.cs:line 166 at SofyImportV3.common.PgpDecrypter.Decrypt(Client client, Stream blobStream, CloudBlobStream decryptedStream, ILogger log) in /Users/kamesh/Desktop/Sofy/SofyUnit/azure_functions/SofyImportV3/common/PGPDecrypter.cs:line 131

WriteOutputAndSignAsync hangs on "await literalOut.WriteAsync(buf, 0, length)"

Calling code:

using (var inputMemoryStream = new MemoryStream(Encoding.UTF8.GetBytes(unsignedString)))
using (var outputMemoryStream = new MemoryStream())
using (var privateKeyStream = new MemoryStream(Encoding.UTF8.GetBytes(key)))
{
       pgp.SignStream(inputMemoryStream, outputMemoryStream, privateKeyStream, password);
       signedString = (new StreamReader(outputMemoryStream)).ReadToEnd();
}

Given "foobar" for unsignedString, SignStream hangs at the point of writing out to literalOut, whereas unsignedString=string.Empty returns instantly (with string.Empty).

Am I doing anything wrong? No error decoding my key, which was my main reason for testing this before handing it real values. Could it be the key itself?

Missing pgp.EncryptStreamAndSignAsync(...)

I need this method

public async Task EncryptStreamAndSignAsync(Stream inputStream , Stream outputStream, Stream publicKeyStream, Stream privateKeyStream, string passPhrase, bool armor = true, bool withIntegrityCheck = true)
{
await Task.Run(() => EncryptStreamAndSign(inputStream, outputStream, publicKeyStream, privateKeyStream, passPhrase, armor, withIntegrityCheck));
}

Using PGPCore in AzureFunctions with EncryptStream

I've tried utilizing this library within Azure functions and having issues with the encryption methods for Streams.
When I EncryptStream, the output does not seem to be formatted correctly because i am unable to decrypt, getting an exception because PgpObjectFactory.NextPgpObject is null.
If I utilize EncryptFile and DecryptFile everything works.
Even if I EncryptFile and then convert that to a stream and DecryptStream, it works.
I'm going to use this in Azure Functions integrated with Azure storage for the files and Azure KeyVault for my pgp keys/passphrase/etc so the stream methods are what I want to get working.
Any idea what my issue is?

Org.BouncyCastle.Bcpg.OpenPgp.PgpException: 'Checksum mismatch at 0 of 2'

Used the following code fragment to perform a test of PgpCore. It fails with, "Org.BouncyCastle.Bcpg.OpenPgp.PgpException: 'Checksum mismatch at 0 of 2'" when attempting to decrypt the file.

            // Generate keys
            pgp.GenerateKey(@"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "[email protected]", "passwo0d");
            // Encrypt file
            pgp.EncryptFile(@"sample.pdf", @"sample_pdf_encrypted.pgp", @"C:\TEMP\keys\public.asc", true, true);
            // Decrypt file
            pgp.DecryptFile(@"sample_pdf_encrypted.pgp", @"sample_pdf_UNencrypted.pgp", @"C:\TEMP\keys\private.asc", "passw0rd");

Allow Keys to be Held in Memory

Add an internal keystore to PGP allowing keys to be stored on initialisation.

How to choose desired keys if multiples allowed?

Secret key for messsage not found

Hi, I am trying to decrypt a Stream using an Azure function app in which the function is http triggered and the data to be decrypted is passed into req.body.
The passphrase and key are stored in a vault, I have verified that they work using gpg4win, and that the app can access them and they print out correctly.
Can you help me figure out why I am seeing the error "Secret Key for message cannot be found" when the key, passphrase, and data are being passed correctly?

using System.IO;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using PgpCore;
using System.Threading.Tasks;
using Microsoft.Azure.KeyVault.Models;
using System.Net.Http;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.KeyVault;
using System;
using System.Text;
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;

namespace AzureFunctionsPGPDecrypt
{
public static class PGPDecrypt
{
private static readonly HttpClient client = new HttpClient();
private static ConcurrentDictionary<string, string> secrects = new ConcurrentDictionary<string, string>();

    [FunctionName(nameof(PGPDecrypt))]
    public static IActionResult Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
    HttpRequest req, ILogger log)
    {
        log.LogInformation($"C# HTTP trigger function {nameof(PGPDecrypt)} processed a request.");

    

        string privateKey =  Environment.GetEnvironmentVariable("secretkey", EnvironmentVariableTarget.Process);
        string passPhrase=  Environment.GetEnvironmentVariable("secretphrase", EnvironmentVariableTarget.Process);

        log.LogInformation($"SecretKey: {privateKey}");
        log.LogInformation($"SecretPassPhrase: {passPhrase}");

        if (privateKey == null)
        {
            return new BadRequestObjectResult("Please pass a private key secret identifier on the query string");
        }


        Stream outputStream = new MemoryStream();
        Stream privateKeyStream = GenerateStreamFromString(privateKey);

        var length = privateKeyStream.Length;
        var length2 = req.Body.Length;

        log.LogInformation($"Length private key stream: {length}");
        log.LogInformation($"Length body: {length2}");

//verifying that the streams were not empty

        using (PGP pgp = new PGP())
        {
            

            using (Stream inputStream = req.Body)
            using(outputStream)
            using (privateKeyStream)
            {
            
                pgp.DecryptStreamAsync(inputStream, outputStream, privateKeyStream, passPhrase);
                
                return new OkObjectResult(outputStream);
            }
        }

    }

    

    private static Stream GenerateStreamFromString(string s)
    {
        MemoryStream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream);
        writer.Write(s);
        writer.Flush();
        stream.Position = 0;
        return stream;
    }
}

}

GenerateKey should overwrite file

When generating a key, if the out-file already exists then the output file can become malformed.

pgp.GenerateKey("public.txt", "private.txt", "username", "password", 1024);
pgp.GenerateKey("public.txt", "private.txt", "username", "password", 512);

This example generates a long key, then a shorter key to the same file. The resulting file:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG C# v1.8.5.0

mEsEXc185AECAKdAfTMUCLXi2vRsz0RwOx2OMJuDUAS69kMyYxAYpZkorM/wqoTs
DkL3/X3Eqm0NNqN6BU9EUPzOFord9Le/uTMABRO0CHVzZXJuYW1liFwEEAECAAYF
Al3NwzQACgkQBD+fFOKPU+jIXAH9GyYQCEExNSBoBt4D0yiNi4fb1hjppp0CwfNI
EpHQ5cGgAKzcJ1ks1qlvOzLJfwBkDknGN1uxsRJ7G154vhFnJA==
=gfJE
-----END PGP PUBLIC KEY BLOCK-----
N7Uml6jYu4LJ3id/USTkFBuUOLwnndcsA
/vUtA9PiYg4uFIICGRBvW9EzS/QDgUK8FfJofDXNs2xBMUBiZJV2HBjnLZByC4X3
8BXwbc/NcnhR83ND9xAAw4f/YrpL
=vu/P
-----END PGP PUBLIC KEY BLOCK-----

I would expect that writing the key to the file would use File.WriteAllText() or something similar which overwrites the whole file.

I found where I would make an adjustment:

PgpCore/PgpCore/PGP.cs

Lines 1112 to 1113 in 31479ef

using (Stream pubs = File.Open(publicKeyFilePath, FileMode.OpenOrCreate))
using (Stream pris = File.Open(privateKeyFilePath, FileMode.OpenOrCreate))

Encrypting file with an expired public key

I am using this library to encrypt a zip file. The code is very simple:

using (PGP pgp = new PGP())
{
    pgp.EncryptFile(zipFileFullname, encryptedFileFullname, publicKeysFileFullname);
}

It generally works well, but today I noticed that if I use an expired public key, it successfully encrypts the file regardless of the key being expired, without any warning. I have been looking for some parameters to be passed or some methods to call to verify if the keys are valid, but I didn't find anything.
Isn't the encryption supposed to fail if the encryption keys expired?

Decrypting Signed + Encrypted Files

Hi, I'm sorry if this is a repeat of issue #6 but I just wanted to clarify.

Does PgpCore have the ability to decrypt signed files? In issue #6 it specifies that it cannot decrypt files that were created from the EncryptFileandSign method, but does that extend to any files that are encrypted and signed period?

In your read me file you provide an example of decrypting a signed file but it doesn't show where it would acquire reference to the public key so I figured it couldn't hurt to ask.

Thanks in advance for your insight.

Add method to extract clear signed content

Hi @tkaradimitris, DecryptFileAndVerify is intended for decrypting and verifying encrypted and signed files which is why it requires both a public and private key. There's currently no functionality for extracting the clear signed content as I'd figured these message would mostly be being read by humans.

If this is something that you need then feel free to submit a PR if you're able, or if not I'll add it to my work list and get to it when I have a chance.

Thank you @mattosaurus for the answer and the great work. I am not sure what I need to use from BouncyCastle to extract content from signed files / streams, but if I manage to find examples from other solutions I will try to submit a PR.

Originally posted by @tkaradimitris in #40 (comment)

Can't decrypt signed and encrypted files

The DecryptFile function doesn't decrypt files that have been encrypted and signed using EncryptFileAndSign, the following error is returned.

Encrypted message contains a signed message - not literal data.

Decrypting a very large file fails

I'm trying to PGP decrypt a very large file via an Azure function using PgpCore, however whilst the output is processed quite quickly for test files (for example a 512Mb file gets decrypted in less than a minute) decrypting very large files (for example 20GB) fails.

We have a timeout on the Azure function of 6 hours, but the process never seems to complete.

The decryption code is quite simple:

using (Stream inputFileStream = await storageAccess.OpenFileStreamAsync(container, encryptedFilePath))
{
  using (Stream outputFileStream = await storageAccess.OpenWritableStreamAsync(container, outputFilePath))
  {
    using (Stream privateKeyStream = await GetPrivateKeyStream())
    {
      using (PGP pgp = new PGP())
      {
        logging.LogInformation($"Decrypting {encryptedFilePath} to {destinationDirectory}");

        pgp.DecryptStream(inputFileStream, outputFileStream, privateKeyStream, password);

        logging.LogInformation($"Decryption complete for {encryptedFilePath}");
      }
    }
  }
}

Where OpenWritableStreamAsync returns a blockBlob.OpenWriteAsync() and OpenFileStreamAsync returns a blockBlob.OpenReadAsync()

I've looked and I can't find any reference of the maximum size file that can be processed, let alone how to change this, or any examples of decrypting using buffered input streaming.

Is there something failing internally here, or is it just a case of taking over 6 hours or filling the available memory?

Thanks

return decrypted data as a Stream (rather than file)

Hello @mattosaurus ,

Is it possible to return the decrypted data as a Stream (accessing outputStream) rather than as a file as you did in the test case?

// Test File example
using (FileStream inputFileStream = new FileStream(contentFilePath, FileMode.Open))
using (Stream outputFileStream = File.Create(encryptedContentFilePath))
using (Stream publicKeyStream = new FileStream(publicKeyFilePath1, FileMode.Open))
using (Stream privateKeyStream = new FileStream(privateKeyFilePath1, FileMode.Open))
pgp.EncryptStreamAndSign(inputFileStream, outputFileStream, publicKeyStream, privateKeyStream, password1);

        using (FileStream inputFileStream = new FileStream(encryptedContentFilePath, FileMode.Open))
        using (Stream outputFileStream = File.Create(decryptedContentFilePath1))
        using (Stream privateKeyStream = new FileStream(privateKeyFilePath1, FileMode.Open))
            pgp.DecryptStream(inputFileStream, outputFileStream, privateKeyStream, password1);

        string decryptedContent = File.ReadAllText(decryptedContentFilePath1);

//My attempt at accessing the stream directly
//outputStream is null

Stream outputStream = new MemoryStream();
Stream privateKeyStream = GenerateStreamFromString(privateKey);

        var length = privateKeyStream.Length;
        var length2 = req.Body.Length;


        
        using (PGP pgp = new PGP())
        {
            

            using (Stream inputStream = req.Body)
            using(outputStream)
            using (privateKeyStream)
            {
                inputStream.Seek(0, SeekOrigin.Begin);
                privateKeyStream.Seek(0, SeekOrigin.Begin);
                outputStream.Seek(0, SeekOrigin.Begin);
                pgp.DecryptStreamAsync(inputStream, outputStream, privateKeyStream, passPhrase);
                log.LogInformation($"decryption complete");
                outputStream.Seek(0, SeekOrigin.Begin);
                log.LogInformation($"seek complete");
                var length3 = outputStream.Length;
                log.LogInformation($"check stream: {length3}");
                StreamReader reader = new StreamReader(outputStream);
                string decryptedData = reader.ReadToEnd();
                log.LogInformation($"read complete: {decryptedData}");
                dynamic data = JsonConvert.DeserializeObject(decryptedData);
                log.LogInformation($"convert complete:{data}");
                return data != null
                        ? (ActionResult)new OkObjectResult(data)
                        : new BadRequestObjectResult("Data not found");
                //return outputStream;
            }
        }

Missing Bytes After Encrypt and Decrypt Large files

Not too sure if anyone have experience this, I've tried to test if the PGP works on large files using the settings below.

        using (PGP pgp = new PGP()
        {
            CompressionAlgorithm = Org.BouncyCastle.Bcpg.CompressionAlgorithmTag.Uncompressed,
            SymmetricKeyAlgorithm = Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag.Aes256,
            PublicKeyAlgorithm = Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag.RsaSign,
            HashAlgorithmTag = Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha512,
            FileType = PGPFileType.Binary,
            PgpSignatureType = PgpSignature.BinaryDocument
        })

So far for smaller files (<1GB) I'm getting exactly same size after the encrypt and decrypt process. but for 1 of my sql server db backup that is sized at 6GB, there's a 53KB mismatched, and resulting in a corrupted file.

image

Error encrypting large file

Hi.
I'm trying to encrypt/decrypt a large file (~7gb) but I'm getting a error

   at System.IO.MemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
   at Org.BouncyCastle.Bcpg.BcpgOutputStream.PartialFlush(Boolean isLast)
   at Org.BouncyCastle.Bcpg.BcpgOutputStream.WritePartial(Byte[] buffer, Int32 off, Int32 len)
   at PgpCore.Utilities.PipeStreamContents(Stream input, Stream pOut, Int32 bufSize)
   at PgpCore.PGP.EncryptStream(Stream inputStream, Stream outputStream, IEnumerable`1 publicKeyStreams, Boolean armor, Boolean withIntegrityCheck)
   at PgpCore.PGP.<>c__DisplayClass25_0.<EncryptStreamAsync>b__0()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
--- End of stack trace from previous location where exception was thrown ---
   at PgpCore.PGP.EncryptStreamAsync(Stream inputStream, Stream outputStream, Stream publicKeyStream, Boolean armor, Boolean withIntegrityCheck)
   at PgpProcessor.Encrypt(String pubKeyPath, String inputFilePath, String outputFilePath) in C:\AgodaGit\aes\dotnet\PgpProcessor.cs:line 15
   at aes.Program.Main(String[] args) in C:\AgodaGit\aes\dotnet\Program.cs:line 33
   at aes.Program.<Main>(String[] args)

Created a bufferSize to output buffer but didn't work

using System.IO;
using System.Threading.Tasks;
using PgpCore;

public class PgpProcessor
{
    private const int bufferSize = 8 * 1024;

    public static async Task Encrypt(string pubKeyPath, string inputFilePath, string outputFilePath)
    {
        using (PGP pgp = new PGP())
        using (FileStream inputFileStream = new FileStream(inputFilePath, FileMode.Open))
        using (Stream outputFileStream = File.Create(outputFilePath, bufferSize))
        using (Stream publicKeyStream = new FileStream(pubKeyPath, FileMode.Open))
            await pgp.EncryptStreamAsync(inputFileStream, outputFileStream, publicKeyStream, false, false);
    }

    public static async Task Decrypt(string privKeyPath, string password, string inputFilePath, string outputFilePath)
    {
        using (PGP pgp = new PGP())
        using (FileStream inputFileStream = new FileStream(inputFilePath, FileMode.Open))
        using (Stream outputFileStream = File.Create(outputFilePath, bufferSize))
        using (Stream privateKeyStream = new FileStream(privKeyPath, FileMode.Open))
            await pgp.DecryptStreamAsync(inputFileStream, outputFileStream, privateKeyStream, password);
    }
}

Thanks!

ClearSignStream fails if any line in the stream has trailing whitespaces

After hours of debugging, I've tracked down an inconsistency in this library compared to gpg (on Windows at least):

Any text that contains a line which ends in spaces (i.e. " \n", " \r\n" or similar) will produce a file which can be verified with PgpCore (i.e. VerifyClearStream), but will fail validation with gpg (bad signature).

Example:

var text = "Test \nString";
using var inputStream = new MemoryStream(Encoding.ASCII.GetBytes(text));
using var outputStream = new MemoryStream();
using var keyStream = File.OpenRead("key.pgp");
var keyPassword = "<boing>";

var pgp = new PGP()
{
    CompressionAlgorithm = Org.BouncyCastle.Bcpg.CompressionAlgorithmTag.Uncompressed,
    FileType = PGPFileType.Binary,
    HashAlgorithmTag = Org.BouncyCastle.Bcpg.HashAlgorithmTag.Sha512,
    PublicKeyAlgorithm = Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag.RsaSign,
    PgpSignatureType = 0
};

pgp.ClearSignStream(inputStream, outputStream, keyStream, keyPassword);

File.WriteAllBytes("borked.txt.asc", outputStream.ToArray());

var gpg = Process.Start("gpg", "--verify borked.txt.asc");
gpg.WaitForExit();
Console.WriteLine(gpg.ExitCode);

This will return 1 for any text which has a line with trailing whitespaces, and 0 for those without. As far as I can tell, there have been some arguments in the PGP/GPG community in the past about how this should be handled (with Binary as proposed solution to avoid this issue altogether), but none of the options in PgpCore seem to be able to create a clear signed file which can be verified by gpg.

Encrypt and Sign is hitting an error

When using "EncryptyStreamAndSign" or "EncryptFileAndSign" in Azure Functions I am hitting an error,
[Error] Executed 'Functions.HttpTrigger1' (Failed, Id=6486b525-e10f-4571-b721-85ef66ffecc8)
Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing found where PgpSecretKeyRing expected

I don't know how to fix this?
As far as I can tell I am using BouncyCastle version 1.8.2

Sample (Usage on README.md) generating incomplete Public and Private Keys

Hi @mattosaurus ,

Thanks for the great library. Trying to setup sample provided on README.md using the same code. Found below issues. Can you guide me on fixing them?

  • GenerateKey(with strength 1024 or 2048) generates both public and private key as incomplete.
  • EncrpyFile and DecryptFile methods not working on generated keys - but works with keys generated from PGP Key generator given on README.MD.

Code:
pgp.GenerateKey(@"C:\TEMP\keys\public.asc", @"C:\TEMP\keys\private.asc", "[email protected]", "password");

Issues:

  1. Both public and private key version line missing BCPG version number.
    Actual Result: BCPG C# v
    Expected Result: BCPG C# v1.8.1.3
  2. Both public and private key does not include end key block
    Actual Result: No end key block on last line
    Expected Result: -----END PGP PUBLIC KEY BLOCK-----

Sample public key(extension renamed to txt for Github to support upload):
public.asc.txt

Sample private key(extension renamed to txt for Github to support upload):
private.asc.txt

EncryptStream using MemoryStream output (no file output)

Hello,

I'm starting C# development so i'm very bad.

This is my code :

            PGP pgp = new PGP();

            Stream inputFileStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("test_basic_messsage"));
            Stream outputFileStream = new MemoryStream();
            Stream publicKeyStream = new FileStream(Utils.app_directory + @"keys\public.asc", FileMode.Open);

            pgp.EncryptStream(inputFileStream, outputFileStream, publicKeyStream);

            StreamReader reader = new StreamReader(outputFileStream);
            string text = reader.ReadToEnd();

            MessageBox.Show(outputFileStream.Length.ToString()); //Messagebox to see outputFileStream length (it display 890)
            MessageBox.Show(text); //Messagebox to see pgp Message (it display nothing)
            MessageBox.Show(text.Length.ToString()); //Messagebox to see pgp message length (it display 0)

I'm trying to store a pgp message in a string variable but i cannot, with this code, outputFileStream.Length equals to 890 but reader.ReadToEnd() equals to nothing.

But when i replace Stream outputFileStream = new MemoryStream(); by Stream outputFileStream = File.Create(Utils.app_directory + @"keys\content.pgp") it's working because i see the pgp message in the content.pgp file...

Sorry for my bad english, i'm french...

Synchronous functions causes deadlocks

This issue is the reason of the behaviour in #44 .

The synchronous versions of the public methods (e.g. EncryptStream) are just calls to the async version of that method (e.g. EncryptStreamAsync) suffixed with .Wait().

Example:
EncryptStreamAsync(inputStream, outputStream, publicKeyStreams, armor, withIntegrityCheck).Wait();

You should never do this because it causes deadlocks, let me try to explain why:

Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. When the code reaches an await statement, it returns an uncompleted task. When this Tasks completes, it wants to synchronize with the request context from where the Task is initiated. It will wait until this thread comes available. Because the Wait() method blocks the current thread, it will never become available: deadlock.

As a general rule, you should use "async all the way down"; that is, don't block on async code.
What you should do is make the synchronous methods truly synchronous, or, remove them so the calling clients are forced to use the async methods.

There is another option though, but it is more or less a hack: suffix every async call with ConfigureAwait(false). This will prevent the task from synchronizing back with the current request context, avoiding a deadlock.

Here is a good read about this topic.

error when decrypting.

Below is my code, we genreated the pgp key pair using Go anywhere software, the code is reading the public key of the sender but giving error on reading my private key.The error is "Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing found where PgpSecretKeyRing expected". Please help its urgent.

        PGPDecrypt test = new PGPDecrypt(@"d:\PGP_Keys\TestKeys\INT328.txt.pgp",
                                            @"d:/PGP_Keys/TestKey/My secret key.asc",
                                            "XXXX",
                                            path1,
                                            @"d:/PGP_Keys/TestKey/Sender public key.asc", true);
        FileStream fs = File.Open(@"d:\PGP_Keys\TestKeys\INT328.txt.pgp", FileMode.Open);
            test.decrypt(fs, path1);
            fs.Close();

public class PgpEncryptionKeys
{
public PgpPublicKey PublicKey { get; private set; }
public PgpPrivateKey PrivateKey { get; private set; }
public PgpSecretKey SecretKey { get; private set; }

    /// <summary>
    /// 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.
    /// </summary>

    /// <param name="publicKeyPath">The key used to encrypt the data</param>
    /// <param name="privateKeyPath">The key used to sign the data.</param>
    /// <param name="passPhrase">The (your) password required to access the private key</param>
    /// <exception cref="ArgumentException">Public key not found. Private key not found. Missing password</exception>

    public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase,bool toEncrypt)
    {

        if (!File.Exists(publicKeyPath))
            throw new ArgumentException("Public key file not found", "publicKeyPath");

        if (!File.Exists(privateKeyPath))
            throw new ArgumentException("Private key file not found", "privateKeyPath");

        if (String.IsNullOrEmpty(passPhrase))
            throw new ArgumentException("passPhrase is null or empty.", "passPhrase");

        PublicKey = ReadPublicKey(publicKeyPath);
        SecretKey = ReadSecretKey(privateKeyPath, toEncrypt);
        PrivateKey = ReadPrivateKey(passPhrase);

    }

    #region Secret Key
    /// <summary>
    /// Return the last key we can use to decrypt.
    /// Note: A file can contain multiple keys (stored in "key rings")
    /// </summary>
    private PgpSecretKey GetLastSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle)
    {
        return (from PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings()
                select kRing.GetSecretKeys().Cast<PgpSecretKey>()
                                                .LastOrDefault(k => k.IsSigningKey))
                                                .LastOrDefault(key => key != null);
    }
    private PgpSecretKey ReadSecretKey(string privateKeyPath, bool toEncrypt)
    {
        using (Stream keyIn = File.OpenRead(privateKeyPath))
        using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
        {
            PgpSecretKeyRingBundle secretKeyRingBundle = new PgpSecretKeyRingBundle(inputStream);
            PgpSecretKey foundKey = toEncrypt ? GetFirstSecretKey(secretKeyRingBundle): GetLastSecretKey(secretKeyRingBundle);
            // PgpSecretKey foundKey = GetFirstSecretKey(secretKeyRingBundle);
            if (foundKey != null)
                return foundKey;
        }
        throw new ArgumentException("Can't find signing key in key ring.");
    }

    /// <summary>
    /// Return the first key we can use to encrypt.
    /// Note: A file can contain multiple keys (stored in "key rings")
    /// </summary>
    private PgpSecretKey GetFirstSecretKey(PgpSecretKeyRingBundle secretKeyRingBundle)
    {
        foreach (PgpSecretKeyRing kRing in secretKeyRingBundle.GetKeyRings())
        {
            PgpSecretKey key = kRing.GetSecretKeys().Cast<PgpSecretKey>().Where(k => k.IsSigningKey).FirstOrDefault();

            if (key != null)
                return key;
        }
        return null;
    }

    #endregion

    #region Public Key
    private PgpPublicKey ReadPublicKey(string publicKeyPath)
    {
        using (Stream keyIn = File.OpenRead(publicKeyPath))
        using (Stream inputStream = PgpUtilities.GetDecoderStream(keyIn))
        {
            PgpPublicKeyRingBundle publicKeyRingBundle = new PgpPublicKeyRingBundle(inputStream);
            PgpPublicKey foundKey = GetFirstPublicKey(publicKeyRingBundle);
            if (foundKey != null)
                return foundKey;
        }
        throw new ArgumentException("No encryption key found in public key ring.");
    }

    private PgpPublicKey GetFirstPublicKey(PgpPublicKeyRingBundle publicKeyRingBundle)
    {

        foreach (PgpPublicKeyRing kRing in publicKeyRingBundle.GetKeyRings())
        {
            PgpPublicKey key = kRing.GetPublicKeys()
                .Cast<PgpPublicKey>()
                .Where(k => k.IsEncryptionKey)
                .FirstOrDefault();

            if (key != null)
                return key;
        }
        return null;
    }

    #endregion

    #region Private Key

    private PgpPrivateKey ReadPrivateKey(string passPhrase)
    {
        PgpPrivateKey privateKey = SecretKey.ExtractPrivateKey(passPhrase.ToCharArray());
        if (privateKey != null)
            return privateKey;

        throw new ArgumentException("No private key found in secret key.");

    }

    #endregion
}

Large memory usage when decrypting not-large file

We are using DecryptStreamAsync() to decrypt a FileStream into a MemoryStream but when we do this with a 24MB FileStream we end up with a 1GB MemoryStream. However when decrypt a smaller FileStream (ie. 7.4KB) we end up with a similar-sized MemoryStream. What would cause this?

Attached are screenshots of the variables in question. encryptedData is the FileStream and result is the MemoryStream.

Thanks!

24mbfilelocals-public
7kbfilelocals-public

Add a license

Hi!

Could you add a license? Perhaps MIT, like ChoPGP?

Getting Secret key for message not found. error when decrypt

Hi,
I'm getting the Secret key for message not found when i try to decrypt a encrypt and signed file.
I have attach my project so you can try.
I have a private key which i have generated and a public key from my external partner where i have to send the encrypt and signed file.
Then encryption part works fine, but when I try to decrypt the encrypt and signed file I get the metioned error.
I have checked that i'm using the right private key, password and i'm using the same private key for decryption which I used to encrypt.

I have attached my C# project, just build it.

Try this flow:

PS. I have not attach the private and public key, because we use these keys in real test environment.

  1. Point to your input file, private key and public key
  2. Start the console app
  3. press E for encryption
  4. when the encryption and sign is finished press enter for exit.

now

1.Point to the same private key
2. Start the console app
3. Press D for decryption
4. You will get the error.

Hope you can tell me why i'm getting this error.

PGP_POC.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.