Вопрос

using the command line gnupg i can create a key ring with a RSA key for "John Doe <john@doe.com>". I can also add another user with uid "Jane Doe <jane@doe.com>" using --edit-key and adduid. The resulting secring.gpg then looks like this:

$ gpg -vv secring.gpg
:secret key packet:
        version 4, algo 1, created 1380898817, expires 0
        skey[0]: [2048 bits]
        skey[1]: [17 bits]
        iter+salt S2K, algo: 9, SHA1 protection, hash: 2, salt: 3825c4409323d7b0
        protect count: 65536 (96)
        protect IV:  ac f9 8d 4a b7 3a 5d 7c b2 3c 28 ff 82 6d 4c ef
        encrypted stuff follows
:user ID packet: "John Doe <john@doe.com>"
:signature packet: algo 1, keyid 9991E2282A9906C7
        version 4, created 1380898818, md5len 0, sigclass 0x13
        digest algo 2, begin of digest bd 01
        hashed subpkt 2 len 4 (sig created 2013-10-04)
        hashed subpkt 27 len 1 (key flags: 03)
        hashed subpkt 11 len 5 (pref-sym-algos: 9 8 7 3 2)
        hashed subpkt 21 len 5 (pref-hash-algos: 8 2 9 10 11)
        hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
        hashed subpkt 30 len 1 (features: 01)
        subpkt 16 len 8 (issuer key ID 9991E2282A9906C7)
        data: [2045 bits]
:trust packet: flag=00 sigcache=00
:user ID packet: "Jane Doe <jane@doe.com>"
:signature packet: algo 1, keyid 9991E2282A9906C7
        version 4, created 1380899570, md5len 0, sigclass 0x13
        digest algo 2, begin of digest 2f 50
        hashed subpkt 2 len 4 (sig created 2013-10-04)
        hashed subpkt 27 len 1 (key flags: 03)
        hashed subpkt 11 len 5 (pref-sym-algos: 9 8 7 3 2)
        hashed subpkt 21 len 5 (pref-hash-algos: 8 2 9 10 11)
        hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
        hashed subpkt 30 len 1 (features: 01)
        hashed subpkt 23 len 1 (key server preferences: 80)
        subpkt 16 len 8 (issuer key ID 9991E2282A9906C7)
        data: [2047 bits]
:trust packet: flag=00 sigcache=00
sec  2048R/2A9906C7 2013-10-04 John Doe <john@doe.com>
sig        2A9906C7 2013-10-04   [selfsig]
uid                            Jane Doe <jane@doe.com>
sig        2A9906C7 2013-10-04   [selfsig]

I'd like to create the same in Java, using Bouncycastle, starting from a java.security.KeyPair, i.e. with a signature like this:

public void createKeyRing(KeyPair keyPair, char[] pass, String[] ids)

where pass is the passphrase and ids = new String[] {"John Doe <john@doe.com>", "Jane Doe <jane@doe.com>"}. I followed the lines of this tutorial, where the key part of the code is:

PGPKeyRingGenerator keyRingGen =
    new PGPKeyRingGenerator(
        PGPSignature.POSITIVE_CERTIFICATION, rsakp_sign,
        id, sha1Calc, signhashgen.generate(), null,
        new BcPGPContentSignerBuilder(
            rsakp_sign.getPublicKey().getAlgorithm(),
            HashAlgorithmTags.SHA1),
        pske);

// Add our encryption subkey, together with its signature.
keyRingGen.addSubKey(rsakp_enc, enchashgen.generate(), null);

where rsakp_sign and rsakp_enc are the RSA keypairs of the sign and encryption keys, respectively, and signhashgen and enchashgen are the generators for the subpackets that contain algorithm preferences and such.

As long as i only create a key for John, all is well. But when i want to add Jane, i run into a problem: apparently i can not add a signhashgen-ified keypair for Jane using addSubKey. The first naive attempt goes like this:

PGPSignatureGenerator sGen = new PGPSignatureGenerator(
  new BcPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, PGPUtil.SHA1));
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, pgpPrivateKey);
PGPSignature certification = sGen.generateCertification("Jane Doe <jane@doe.com>", pgpPublicKey);

PGPPublicKey newKey = PGPPublicKey.addCertification(pgpPublicKey, "Jane Doe <jane@doe.com>", certification);

keyRingGen.addSubKey(new PGPKeyPair(newKey, pgpPrivateKey), enchashgen.generate(), null);

and that just doesn't do anything, no additional entries show up in gpg --vv meeththedoes.asc.

Alternatively, i can take John's keyring, extract the secret key, and then add Jane:

PGPSecretKeyRing keyRing = keyRingGen.generateSecretKeyRing();

PGPSecretKey pgpSecretKey = keyRing.getSecretKey();
BcPGPDigestCalculatorProvider calculatorProvider = new BcPGPDigestCalculatorProvider();
BcPBESecretKeyDecryptorBuilder decryptor = new BcPBESecretKeyDecryptorBuilder(calculatorProvider);
PGPPrivateKey pgpPrivateKey = pgpSecretKey.extractPrivateKey(decryptor.build(pass));    
PGPPublicKey pgpPublicKey = pgpSecretKey.getPublicKey();

PGPSignatureGenerator    sGen = new PGPSignatureGenerator(
  new BcPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, PGPUtil.SHA1));
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, pgpPrivateKey);
PGPSignature certification = sGen.generateCertification("Jane Doe <jane@doe.com>", pgpPublicKey);

PGPPublicKey newKey = PGPPublicKey.addCertification(pgpPublicKey, "Jane Doe <jane@doe.com>", certification);

pgpSecretKey = PGPSecretKey.replacePublicKey(pgpSecretKey, newKey);

This kinda works, but in the resulting key ring John and Jane have different sets of subpackets:

$ gpg -vv meetthedoes.asc
gpg: ASCII-Hülle: BEGIN PGP PRIVATE KEY BLOCK
gpg: ASCII-Hülle: Version: BCPG v1.48
:secret key packet:
        version 4, algo 3, created 1380908986, expires 0
        skey[0]: [2048 bits]
        skey[1]: [17 bits]
        iter+salt S2K, algo: 9, SHA1 protection, hash: 2, salt: 696d2d42bd6b727c
        protect count: 65536 (96)
        protect IV:  87 31 81 df 17 fa 74 c4 c3 35 39 26 98 c1 15 27
        encrypted stuff follows
:user ID packet: "John Doe <john@doe.com>"
:signature packet: algo 3, keyid 3A80073198CF2010
        version 4, created 1380908986, md5len 0, sigclass 0x13
        digest algo 2, begin of digest a5 c8
        hashed subpkt 2 len 4 (sig created 2013-10-04)
        hashed subpkt 27 len 1 (key flags: 03)
        hashed subpkt 11 len 5 (pref-sym-algos: 9 8 7 3 2)
        hashed subpkt 21 len 5 (pref-hash-algos: 8 2 9 10 11)
        hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
        hashed subpkt 30 len 1 (features: 01)
        subpkt 16 len 8 (issuer key ID 3A80073198CF2010)
        data: [2047 bits]
:user ID packet: "Jane Doe <jane@doe.com>"
:signature packet: algo 3, keyid 3A80073198CF2010
        version 4, created 1380908986, md5len 0, sigclass 0x13
        digest algo 2, begin of digest f6 e8
        hashed subpkt 2 len 4 (sig created 2013-10-04)
        subpkt 16 len 8 (issuer key ID 3A80073198CF2010)
        data: [2039 bits]
sec  2048s/98CF2010 2013-10-04 John Doe <john@doe.com>
sig        98CF2010 2013-10-04   [selfsig]
uid                            Jane Doe <jane@doe.com>
sig        98CF2010 2013-10-04   [selfsig]

which i probably don't want, right? In any case, the method seems wrong, too. Shouldn't i be able to instrument the generator completely first, and then have Bouncycastle generate the key ring file in one fell swoop? What am i doing wrong here?

Это было полезно?

Решение

The API apparently differs between adding the first and subsequent uids. For John, i can say

PGPKeyRingGenerator generator = new PGPKeyRingGenerator(
  PGPSignature.POSITIVE_CERTIFICATION, 
  signKeyPair, john, sha1Calc,
  signhashgen.generate(), null,
  new BcPGPContentSignerBuilder(
    signKeyPair.getPublicKey().getAlgorithm(),
    HashAlgorithmTags.SHA1),
    new BcPBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256).build(pass)
);    
generator.addSubKey(encKeyPair, enchashgen.generate(), null);    
PGPSecretKeyRing ring = generator.generateSecretKeyRing();

and that creates the secret key ring with signing key plus encryption subkey, just the way gnupgp does it. But for Jane, that doesn't work, because the signhashgen that would carry information about her subkey is not an argument of addSubKey. Instead i can extract John's secret key from the ring, create a PGPPrivateKey from it and use this to sign Jane's uid.

PGPSignatureGenerator generator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(PGPPublicKey.RSA_GENERAL,
  PGPUtil.SHA1)); 
generator.init(PGPSignature.POSITIVE_CERTIFICATION, johnsPrivateKey);
PGPSignatureSubpacketGenerator signhashgen = copyJohnsSignhashgen();      
generator.setHashedSubpackets(signhashgen.generate());    
PGPSignature certification = generator.generateCertification(jane, getEncryptionKey(secretKeyRing));
PGPPublicKey janesKey = PGPPublicKey.addCertification(getEncryptionKey(secretKeyRing), jane, certification);

All that's left to do is add the new key to the keyring.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top