3

I was trying to decrypt this sample file given by the client, using a class called PgpDecrypt. But when the code comes to this line:

Stream clear = pbe.GetDataStream(privKey);

it returns an error: exception decrypting secret key

Here's my decryption code:

PgpDecrypt test = new PgpDecrypt(string.Concat(pathh, "TestDecryptionFile"),
                                             string.Concat(pathh, "mypgpprivatekey.key"),
                                             "mypassphrase",
                                             @"d:/test/",
                                             string.Concat(pathh, "clientpublickey.key"));

FileStream fs = File.Open(string.Concat(pathh, "TestDecryptionFile"), FileMode.Open);
test.Decrypt(fs, @"d:\test\");

I am using BouncyCastle as my third party library for .NET.

Any idea to solve this would be a great help. Thanks in advance!

iceheaven31
  • 877
  • 1
  • 13
  • 23
  • local path where the files are... @"D:\Users\MyUser\Documents\Visual Studio 2008\Projects\sFTPwithPGP\keys\keys26112012\" – iceheaven31 Dec 03 '12 at 08:13
  • 1
    For added safety when building paths you should use [Path.Combine](http://msdn.microsoft.com/en-us/library/system.io.path.combine.aspx). – Sani Huttunen Dec 03 '12 at 08:32
  • Have you checked the access rights so that the application can access the PGP keys? – Sani Huttunen Dec 03 '12 at 08:33
  • i believe there is no issue with regards to access rights since im using the same approach (pathh, filename) when accessing the keys because i can successfully encrypt a file.. the problem now is i cant decrypt a file encrypted by the client.. >. – iceheaven31 Dec 03 '12 at 09:04

1 Answers1

6

If you're following the BouncyCastle classes PGPEncrypt, PGPDecrypt and PGPEncryptionKeys...

Under the PGPEncryptionKeys class, add this method:

/// <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);
}

still inside the PgpEncryptionKeys class, make sure the ReadSecretKey method looks like this:

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);

        if (foundKey != null)
            return foundKey;
    }
    throw new ArgumentException("Can't find signing key in key ring.");
}

^_^

iceheaven31
  • 877
  • 1
  • 13
  • 23
  • 1
    Worked perfect. For anyone who stumbles on this, don't forget to modify the constructor as such: `public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase, bool toEncrypt)` – Corwin01 Sep 20 '13 at 21:05
  • 1
    Yep. Working perfectly now =) – Corwin01 Dec 11 '13 at 22:19
  • I am getting exactly the same error, and I am using the same classes, I added this function in `PgpEncryptionKeys` but still getting same exception – Umm E Habiba Siddiqui Apr 11 '16 at 19:32
  • Where is GetFirstSecretKey defined in this example? – Matt Jul 18 '17 at 23:58
  • @Matt: It's already pre-existing in the library, unlike the GetLastSecretKey method which we manually added ourselves. But for your reference, GetFirstSecretKey is almost the same as GetLastSecretKey, except that the .LastOrDefault statement in GetLastSecretKey is .FirstOrDefault in GetFirstSecretKey. – iceheaven31 Oct 27 '17 at 09:46