mattosaurus / PgpCore

.NET Core class library for using PGP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Get content from message generated by SignArmoredStringAsync

MrPsi opened this issue · comments

Hi,

Is it possible to get the content from the message generated by the SignArmoredStringAsync method?

When we run SignArmoredStringAsync("our message") PgpCore will generate a message as below.

-----BEGIN PGP MESSAGE-----
Version: BouncyCastle.NET Cryptography (net6.0) v2.1.1+851feee009

...xxx...
-----END PGP MESSAGE-----

We can then verify the message by running VerifyArmoredStringAsync. But is it possible to get the content, in this case "our message" using PgpCore?

Using gnupg we can get the content by running :
gpg --output output.txt --decrypt signed-message.txt

output.txt will in this case contain "our message".

VerifyArmoredStringAsync only returns a bool.
DecryptArmoredStringAsync and DecryptArmoredStringAndVerifyAsync does not work.

Hi again,

I am able to get the content of the signed message by doing the following.
In the method: private Task VerifyAsync(Stream inputStream)

If I change this (in two different places in the method):

int ch;
while ((ch = pgpLiteralStream.ReadByte()) >= 0)
{
    pgpOnePassSignature.Update((byte)ch);
}

To this:

int ch;
var stringBuilder = new StringBuilder();
while ((ch = pgpLiteralStream.ReadByte()) >= 0)
{
    pgpOnePassSignature.Update((byte)ch);
    stringBuilder.Append((char)ch);
}

The string builder will contain the content of the signed message. Not sure if this will work for all scenarios. But it works for the message generated with SignArmoredStringAsync, and also another message where pgpObject is PgpSignatureList (not sure how this is generated).

Hi, you should be able to use VerifyAndReadClearArmoredStringAsync for this. Though it looks like I haven't included these in the documentation so that's something for me to update.

When I run VerifyAndReadClearArmoredStringAsync for the message generated with SignArmoredStringAsync it throws the following

System.IO.IOException: 'unknown object in stream Reserved'

   at Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.NextPgpObject()
   at PgpCore.PGP.<VerifyClearAsync>d__299.MoveNext()
   at PgpCore.PGP.<VerifyAndReadClearArmoredStringAsync>d__265.MoveNext()
   at EncryptDecrypt.PgpEncryptionService.<BisTest>d__2.MoveNext()

And when I run VerifyAndReadClearArmoredStringAsync with the other message (not sure how this is generated) it throws the following:

System.IO.IOException: 'invalid header encountered'

   at Org.BouncyCastle.Bcpg.BcpgInputStream.ReadPacket()
   at Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature..ctor(BcpgInputStream bcpgInput)
   at Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.NextPgpObject()
   at PgpCore.PGP.<VerifyClearAsync>d__299.MoveNext()
   at PgpCore.PGP.<VerifyAndReadClearArmoredStringAsync>d__265.MoveNext()
   at EncryptDecrypt.PgpEncryptionService.<BisTest>d__2.MoveNext()

However both messages gives the content with the above mentioned "hack".

Hmm, possibly a bug then. When decrypting or verifying we check the type of object in an if statement and then act accordingly so possibly there's something missing here.

I'm currently on holiday but can take a look when I'm back in a couple of weeks. If you're able to provide a test scenario that would make things easier. Or better yet a PR fixing the issue :)

Thanks for looking into this.
I just did the following when testing:

        var encryptionKeys = new EncryptionKeys(
            PublicKey,
            PrivateKey,
            PrivateKeyPassword);
        using var pgp = new PGP(encryptionKeys);
        var signedWithContent = await pgp.SignArmoredStringAsync("my content");
        var plainText = (await pgp.VerifyAndReadClearArmoredStringAsync(signedWithContent)).ClearText; 

Not sure I know how to fix it though :)
Please enjoy your holiday

Ok, I had a look at this and VerifyAndReadClearArmoredStringAsync produces a VerificationResult containing a bool and the string content for a clear signed file produced using ClearSignArmoredStringAsync.

However you're just looking at a standard signed file not a clear signed one. There's currently no corresponding methods to decrypt and verify these but I agree that it makes sense to add them. What we need are the following additional methods.

VerifyAndReadArmoredStringAsync
VerifyAndReadStreamAsync
VerifyAndReadFileAsync
VerifyAndReadArmoredString
VerifyAndReadStream
VerifyAndReadFile

I'll see if I can add these using your sample code above.

These should now be added in v5.12.0. I'll publish this to NuGet in a few days once I've taken care of a few more issues.

Awesome! Seems to be working for both my cases.

Thank you for a great update