Java Bouncycastle OpenPGPGPG:如何创建具有两个用户ID的PGP密钥对?

Java Bouncycastle OpenPGPGPG:如何创建具有两个用户ID的PGP密钥对?,java,bouncycastle,openpgp,Java,Bouncycastle,Openpgp,使用命令行gnupg,我可以为“johndoe”创建一个带有RSA密钥的密钥环。我还可以使用--edit key和adduid添加另一个uid为“Jane Doe”的用户。生成的secring.gpg如下所示: $ gpg -vv secring.gpg :secret key packet: version 4, algo 1, created 1380898817, expires 0 skey[0]: [2048 bits] skey[1]:

使用命令行gnupg,我可以为“johndoe”创建一个带有RSA密钥的密钥环。我还可以使用
--edit key
adduid
添加另一个uid为“Jane Doe”的用户。生成的secring.gpg如下所示:

$ 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]
public void createKeyRing(KeyPair keyPair, char[] pass, String[] ids)
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);
其中pass是密码短语,
ids=newstring[]{“John Doe”,“Jane Doe”}
。我遵循的是,其中代码的关键部分是:

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);
其中,rsakp_sign和rsakp_enc分别是签名密钥和加密密钥的RSA密钥对,signhashgen和enchashgen是包含算法首选项等的子包的生成器

只要我只为约翰创造一把钥匙,一切都很好。但当我想添加Jane时,我遇到了一个问题:显然,我无法使用addSubKey为Jane添加signhashgen-ified密钥对。第一次天真的尝试是这样的:

$ 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]
public void createKeyRing(KeyPair keyPair, char[] pass, String[] ids)
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);
这是可行的,但在最终的钥匙圈中,John和Jane有不同的子包集:

$ 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]
$gpg-vv meetthedoes.asc
gpg:ASCII-Hülle:BEGIN PGP私钥块
gpg:ASCII-Hülle:Version:BCPGV1.48
:密钥包:
版本4,Algo3,创建于1380908986,过期0
skey[0]:[2048位]
skey[1]:[17位]
iter+salt S2K,算法:9,SHA1保护,散列:2,salt:696d2d42bd6b727c
保护计数:65536(96)
保护IV:87 31 81 df 17 fa 74 c4 c3 35 39 26 98 c1 15 27
加密的内容如下
:用户ID数据包:“John Doe”
:签名包:algo 3,密钥ID 3A80073198CF2010
版本4,创建1380908986,md5len 0,sigclass 0x13
摘要算法2,摘要a5 c8的开头
散列子目录2第4列(sig创建于2013-10-04)
散列子块27 len 1(关键标志:03)
散列子块11 len 5(pref sym algos:9 8 7 3 2)
散列子块21 len 5(预散列算法:8 2 9 10 11)
散列子块22 len 3(pref-zip-algos:2 3 1)
散列子块30 len 1(特性:01)
子条款16第8节(发卡机构密钥ID 3A80073198CF2010)
数据:[2047位]
:用户ID数据包:“Jane Doe”
:签名包:algo 3,密钥ID 3A80073198CF2010
版本4,创建1380908986,md5len 0,sigclass 0x13
摘要算法2,从摘要f6 e8开始
散列子目录2第4列(sig创建于2013-10-04)
子条款16第8节(发卡机构密钥ID 3A80073198CF2010)
数据:[2039位]
第2048s/98CF2010节2013-10-04约翰·多伊
sig 98CF2010 2013-10-04[selfsig]
无名氏
sig 98CF2010 2013-10-04[selfsig]

我可能不想要,对吧?无论如何,这种方法似乎也是错误的。难道我不应该先完全插入生成器,然后让Bouncycastle一次性生成钥匙圈文件吗?我做错了什么?

添加第一个UID和后续UID的API显然不同。对于约翰,我可以说

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();
这将创建带有签名密钥和加密子密钥的密钥环,就像gnupgp那样。但对于Jane来说,这是行不通的,因为将携带有关其子键的信息的signhashgen不是addSubKey的参数。相反,我可以从戒指中提取John的密钥,从中创建一个PGPPrivateKey,并使用它为Jane的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);
剩下要做的就是将新钥匙添加到钥匙圈中