Closed polterguy closed 8 years ago
You might just need to memStreamPrivate.Position = 0;
before calling ctx.ImportSecretKeys()
Here's what you need to do:
PgpSecretKey secretKey = new PgpSecretKey (
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
kp.Public,
kp.Private,
DateTime.Now,
"foo@bar.com",
SymmetricKeyAlgorithmTag.Cast5,
"password".ToCharArray (),
null,
null,
new SecureRandom());
var ring = new PgpSecretKeyRing (secretKey.GetEncoded ());
var bundle = new PgpSecretKeyRingBundle (new [] { ring });
using (var armored = new ArmoredOutputStream (mem)) {
bundle.Encode (armored);
armored.Flush ();
}
mem.Position = 0;
ctx.ImportSecretKeys (mem);
I probably should have named this ImportSecretKeyringBundle(). I'll probably rename it for 2.0
Thx, but it still doesn't work. Here's my entire code
// Creating our keypair
IAsymmetricCipherKeyPairGenerator kpg = new RsaKeyPairGenerator ();
kpg.Init (new RsaKeyGenerationParameters (BigInteger.ValueOf(0x13), new SecureRandom (), 1024, 8));
AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
// Importing keypair to GnuPG
using (var ctx = new GnuPrivacyContext ()) {
// Serializing key(s) to MemoryStream
using (var memStreamPrivate = new MemoryStream ()) {
PgpSecretKey secretKey = new PgpSecretKey (
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
kp.Public,
kp.Private,
DateTime.Now,
"foo@bar.com",
SymmetricKeyAlgorithmTag.Cast5,
"password".ToCharArray (),
null,
null,
new SecureRandom());
var ring = new PgpSecretKeyRing (secretKey.GetEncoded ());
var bundle = new PgpSecretKeyRingBundle (new [] { ring });
using (var armored = new ArmoredOutputStream (memStreamPrivate)) {
bundle.Encode (armored);
armored.Flush ();
}
memStreamPrivate.Position = 0;
ctx.ImportSecretKeys (memStreamPrivate);
}
}
After executing the above, I open my GPG Keychain, and look for my keys. No new keys are shown though ...?
PS, I am on a Mac OS X, using GPG Tools ... And code is running in ASP.NET app, on top of xsp4 ...
Hmmm, that should have worked... I'll look more today.
Thx, you're a champ :)
PS! No exceptions occurs ... Suggestion, when you invoke "Import", and nothing is imported, maybe it should throw exception or something ...? I've looked through your code, seeing that you check the number of keys that was successfully imported, and only if this is more than "0", you actually save the keyring. Maybe you should have an else here, or something, that does "throw new ArgumentException", or something ...?
Yea, I was thinking about that yesterday.
Okay, so the thing is that the secret key is being imported into secring.gpg, but MimeKit does not add an entry to trustdb.gpg. I'm not sure what the format for that file is, so I'm not sure how to add records to it.
Hmm, a quick search returned this ...
http://unix.stackexchange.com/questions/110500/how-to-regenerate-etc-apt-trustdb-gpg-on-debian
Unfortunately that doesn't help because that's for the system gpg installation where the solution is to just rm -rf the gpg keys and refetch them.
It looks like someone is working on implementing support for gpg's trustdb in the java version of bouncy castle, so it might be possible to port that logic over to c# and get it into c# bouncy castle, but that will probably take a while.
I tried this in a terminal;
rm trustdb.gpg
gpg2 --import-ownertrust
It says; "trustdb created" afterwards. When I open my GPGTools Keychain afterwards, all my old keys are there, without any trust besides the default. None of my generated keys can be found though. I am not sure, but I think trustdb.gpg is only for associating trust with keys, and that you don't really need to fiddle with it in any ways ...?
I am not 100% sure, since it is difficult for me to debug your code, since I am using the nuget version, but I think there is something "fishy" in your "SaveSecretKeyRingBundle" method ...?
PS! If I delete the "trustdb.gpg" file, for then to run my code, for then to open GPGTools Keychain, my "trustdb.gpg" file is re-created, but none of my keys can be found. I even tried to delete my "secring.gpg" file, for then to rename "secring.gpg~" to "secring.gpg", without success ...?
I am not sure, but I don't think the trustdb file is related to the issue ...?
For the record, if I run this code, and open the resulting "foo.asc" in GPGTools, it will import my keys ...
// Creating our keypair
IAsymmetricCipherKeyPairGenerator kpg = new RsaKeyPairGenerator ();
kpg.Init (new RsaKeyGenerationParameters (BigInteger.ValueOf(0x10001), new SecureRandom (), 2048, 12));
AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
// Importing keypair to GnuPG
using (var ctx = new GnuPrivacyContext ()) {
// Serializing key(s) to MemoryStream
using (var memStreamPrivate = new MemoryStream ()) {
// Creating secret PGP key
PgpSecretKey secretKey = new PgpSecretKey (
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
kp.Public,
kp.Private,
DateTime.Now,
"foo2@gmail.com",
SymmetricKeyAlgorithmTag.Cast5,
"$sdfSDFG543y896_-+=".ToCharArray (),
null,
null,
new SecureRandom());
using (var armored = new ArmoredOutputStream (memStreamPrivate)) {
secretKey.Encode (armored);
armored.Flush ();
}
memStreamPrivate.Position = 0;
using (FileStream stream = File.OpenWrite ("/Users/thomashansen/Documents/foo.asc")) {
memStreamPrivate.CopyTo (stream);
}
}
}
But when I wrap my key into a keyring/bundle, no keys are imported ...
Well, I wouldn't expect it to work because gpg probably doesn't know how to import a bundle, it only knows how to import a single key.
BTW, not sure if this was lost in "translation", but I am almost certain that the "trustdb.pgp" file has nothing to do with this ... See above comments ...
I'm pretty sure it works because the unit tests depend on it working... it's possible that the output of saving the bundle isn't completely readable by gpg, but I'm not sure
Also, when I run "gpg2 --list-secret-keys" through shell, it actually show my keys. Only in the GUI of GPGTools my keys don't show. I've tried to use an "invisible key" to encrypt though, without success ...
Heh, I was just about to say I wrote a little unit test and then checked to see if gpg2 could list the secret keys:
[fejj@localhost gpghome]$ cp ../UnitTests/bin/Debug/secring.gpg .
overwrite ./secring.gpg? (y/n [n]) y
[fejj@localhost gpghome]$ cp ../UnitTests/bin/Debug/pubring.gpg .
overwrite ./pubring.gpg? (y/n [n]) y
[fejj@localhost gpghome]$ rm -f trustdb.gpg
[fejj@localhost gpghome]$ GNUPGHOME=. gpg2 --list-secret-keys
gpg: WARNING: unsafe permissions on homedir `.'
gpg: ./trustdb.gpg: trustdb created
./secring.gpg
-------------
sec 1024R/B6FB2584 2016-01-21
uid foo@bar.com
sec 2048R/AB0821A2 2013-11-03
uid MimeKit UnitTests <mimekit@example.com>
ssb 2048R/AA3EA3BA 2013-11-03
So it was definitely imported and written out just fine.
You know what the problem might be? You imported a secret key, but not a public key.
I know, I started slowly realising what was wrong myself ...!! :D Obviously PGPTools won't show a key when it doesn't have a public key ... So then comes the question of how to import the public parts ...? I am assuming "Import" on OpenPGPContext, but importing WHAT ...?
BTW, may I suggest a little "API change". Instead of supplying the stream, how about supplying the "PgpSecretKeyRingBundle" instead, and then have a method that extracts both public and private ...? :)
Maybe mark the current one as "obsolete" ...?
Puuh, OK, got it working. I'll write up a blog post, trying to explain a tiny example of what I did. But basically, this worked .... :)
// Creating our keypair
IAsymmetricCipherKeyPairGenerator kpg = new RsaKeyPairGenerator ();
kpg.Init (new RsaKeyGenerationParameters (BigInteger.ValueOf(0x10001), new SecureRandom (), 1024, 12));
AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
// Importing keypair to GnuPG
using (var ctx = new GnuPrivacyContext ()) {
// Serializing key(s) to MemoryStream
using (var memStreamPrivate = new MemoryStream ()) {
// Creating secret PGP key
PgpSecretKey secretKey = new PgpSecretKey (
PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
kp.Public,
kp.Private,
DateTime.Now.AddYears (3),
"Foo Hansen <foo22@gmail.com>",
SymmetricKeyAlgorithmTag.Cast5,
"foobar".ToCharArray (),
null,
null,
new SecureRandom());
var ring = new PgpSecretKeyRing (secretKey.GetEncoded ());
var bundle = new PgpSecretKeyRingBundle (new [] { ring });
using (var armored = new ArmoredOutputStream (memStreamPrivate)) {
bundle.Encode (armored);
armored.Flush ();
memStreamPrivate.Flush ();
}
memStreamPrivate.Position = 0;
ctx.ImportSecretKeys (memStreamPrivate);
var ring2 = new PgpPublicKeyRing (secretKey.PublicKey.GetEncoded ());
var bundle2 = new PgpPublicKeyRingBundle (new [] { ring2 });
using (var str2 = new MemoryStream ()) {
using (var armored2 = new ArmoredOutputStream (str2)) {
bundle2.Encode (armored2);
armored2.Flush ();
str2.Flush ();
}
str2.Position = 0;
ctx.Import (str2);
}
}
}
The weird part is that unless I have the last "Import" statement AFTER the disposing of the armored2 stream, then it won't work ...? :P
Anyway, thx. I'll write up a blog post about this, such that hopefully the ones coming after me won't have to fiddle as much with it as I did.
PS! Still think the API change, having OpenPGPContext take a "PgpPublicKeyRingBundle" and a "PgpSecretKeyRingBundle" might be a good idea. The "stream" parameter is basically impossible to guess what it should contain ...
Thx, you're a champ, as always :)
I've just added Import() methods that take Pgp[Public,Secret]KeyRing[Bundle]s
Thx :) I think others will appreciate it ...
BTW, for the record ... I don't understand why, but my key is listed as "invalid" in GPGTools. When I look at the key using "Details", it does not seem to associate the public key as a "sub key" of my private key. I can still encrypt and decrypt using the key, but GPGTools doesn't "like it" for some reasons ...?
My guess is that the keys are not associated with each others correctly ...?
Keyrings are how gpg does subkeys, so what I think you need to do is create a PgpSecretKeyRing and add the secret key and then add the public key.
Anyway, I've published MimeKit 1.2.20 that adds the new Import() methods.
Thx Jeffrey, I'll do an update :)
PS! I finally figured out how to create a key ring, with a "master key" and a "sub key" for daily use, etc, and have them correctly associated with each other. Here's a little article about how I use your baby, to create a key pair ...
https://phosphorusfive.wordpress.com/2016/01/26/how-i-create-new-pgp-key-pairs-in-phosphorus-five/
Howdy, I'm fiddling around with trying to create a key pair using BouncyCastle, and figured I'd use the ImportSecretKeys method on OpenPGPContext to import my keys, but it doesn't work. It doesn't throw an error or anything, but when I check out my keys in GPG Keychain (MAC OS X), the keys don't show up ...?
Here is my code ...
Is there something I have misunderstood ...? (which I assume btw)
Basically, what I am trying to achieve, is to create a private/public OpenPGP keypair, and import it into my Keychain ...