Bouncycastle openpgpg: Как создать пару ключей PGP с двумя идентификаторами пользователей?

используя командную строку gnupg, я могу создать связку ключей с ключом RSA для «John Doe‹ [email protected] ›». Я также могу добавить другого пользователя с uid «Jane Doe‹ [email protected] ›», используя --edit-key и adduid. В результате полученный файл 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 <[email protected]>"
: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 <[email protected]>"
: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 <[email protected]>
sig        2A9906C7 2013-10-04   [selfsig]
uid                            Jane Doe <[email protected]>
sig        2A9906C7 2013-10-04   [selfsig]

Я хотел бы создать то же самое на Java, используя Bouncycastle, начиная с java.security.KeyPair, то есть с такой подписью:

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

где pass - кодовая фраза и ids = new String[] {"John Doe <[email protected]>", "Jane Doe <[email protected]>"}. Я следил за строками этого руководства, где ключевой частью кода является:

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 - генераторы для подпакетов, которые содержат настройки алгоритмов и т. д.

Пока я создаю ключ только для Джона, все в порядке. Но когда я хочу добавить Джейн, я сталкиваюсь с проблемой: по-видимому, я не могу добавить пару ключей для Джейн с помощью addSubKey. Первая наивная попытка выглядит так:

PGPSignatureGenerator sGen = new PGPSignatureGenerator(
  new BcPGPContentSignerBuilder(PGPPublicKey.RSA_SIGN, PGPUtil.SHA1));
sGen.init(PGPSignature.POSITIVE_CERTIFICATION, pgpPrivateKey);
PGPSignature certification = sGen.generateCertification("Jane Doe <[email protected]>", pgpPublicKey);

PGPPublicKey newKey = PGPPublicKey.addCertification(pgpPublicKey, "Jane Doe <[email protected]>", certification);

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

и это просто ничего не делает, никаких дополнительных записей в gpg --vv meeththedoes.asc не отображается.

В качестве альтернативы я могу взять связку ключей Джона, извлечь секретный ключ, а затем добавить Джейн:

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 <[email protected]>", pgpPublicKey);

PGPPublicKey newKey = PGPPublicKey.addCertification(pgpPublicKey, "Jane Doe <[email protected]>", certification);

pgpSecretKey = PGPSecretKey.replacePublicKey(pgpSecretKey, newKey);

Это вроде работает, но в результирующем связке ключей Джон и Джейн имеют разные наборы подпакетов:

$ 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 <[email protected]>"
: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 <[email protected]>"
: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 <[email protected]>
sig        98CF2010 2013-10-04   [selfsig]
uid                            Jane Doe <[email protected]>
sig        98CF2010 2013-10-04   [selfsig]

что я, наверное, не хочу, правда? В любом случае, метод тоже кажется неправильным. Разве я не могу сначала полностью настроить генератор, а затем заставить Bouncycastle сгенерировать файл связки ключей одним махом? Что я здесь делаю не так?


person wallenborn    schedule 04.10.2013    source источник


Ответы (1)


API явно различается между добавлением первого и последующих uid. Для Джона я могу сказать

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. Но для Джейн это не сработает, потому что хэшген, который будет нести информацию о ее подключе, не является аргументом addSubKey. Вместо этого я могу извлечь секретный ключ Джона из кольца, создать из него PGPPrivateKey и использовать его для подписи 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);

Все, что осталось сделать, это добавить новый ключ в связку ключей.

person wallenborn    schedule 08.10.2013