Search code examples
c#bouncycastle

How can I verify signature for open PGP using BouncyCastle


How can I verify signature for open PGP using BouncyCastle?

  1. I am using C#
  2. I have pulic key http://itransact.com/support/toolkit/html-connection/pgp.php
  3. I am using BouncyCastle as open pgp library
  4. I have signature that I recieve in query string.
  5. According to instruction (http://itransact.com/downloads/PCFullDocument-4.4.pdf p.145) algorithm is RSA.

I checked a lot of resource but no success. As I understood I need to pass public key and signature to some Verify method.

It is also not clear if I have to convert given public key in string format to some appropriate public key object. If I have to what is the type? I have tried to convert it to RsaKeyParameters but got error message about inappropriate block on public key.

At the moment I have the following code

private bool VerifyWithPublicKey(string data, byte[] sig)
    {
        RSACryptoServiceProvider rsa;

        using (var keyreader = new StringReader(publicKey))
        {
                var pemReader = new PemReader(keyreader);
                var y = (RsaKeyParameters)pemReader.ReadObject();
                rsa = (RSACryptoServiceProvider)RSA.Create();
                var rsaParameters = new RSAParameters();

                rsaParameters.Modulus = y.Modulus.ToByteArray();
                rsaParameters.Exponent = y.Exponent.ToByteArray();
                rsa.ImportParameters(rsaParameters);

                // compute sha1 hash of the data
                var sha = new SHA1CryptoServiceProvider();
                byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

                // This always returns false
                return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), sig);
        }

Solution

  • Using RSA is not your case. You need

    1. Define public key
    2. Convert public ket into PgPPublicKey
    3. Get PgpSignature object
    4. Verify signature

    To verify signature you will need original data that was signed.

    public class iTransactVerifier
    {
        private const string PublicKey = @"-----BEGIN PGP PUBLIC KEY BLOCK-----
    Version: 4.5
    
    mQCNAjZu
    -----END PGP PUBLIC KEY BLOCK-----";
    
        public static bool Verify(string signature, string data)
        {
            var inputStream = ConvertStringToStream(signature);
    
            PgpPublicKey publicKey = ReadPublicKeyFromString();
            var stream = PgpUtilities.GetDecoderStream(inputStream);
    
            PgpObjectFactory pgpFact = new PgpObjectFactory(stream);
    
            PgpSignatureList sList = pgpFact.NextPgpObject() as PgpSignatureList;
            if (sList == null)
            {
                throw new InvalidOperationException("PgpObjectFactory could not create signature list");
            }
            PgpSignature firstSig = sList[0];
    
            firstSig.InitVerify(publicKey);
            firstSig.Update(Encoding.UTF8.GetBytes(data));
    
            var verified = firstSig.Verify();
            return verified;
        }
    
        ....
    
        private static PgpPublicKey ReadPublicKeyFromString()
        {
            var varstream = ConvertStringToStream(PublicKey);
            var stream = PgpUtilities.GetDecoderStream(varstream);
    
            PgpObjectFactory pgpFact = new PgpObjectFactory(stream);
            var keyRing = (PgpPublicKeyRing)pgpFact.NextPgpObject();
            return keyRing.GetPublicKey();
        }
    }