【发布时间】:2021-09-20 10:37:00
【问题描述】:
因此,以下代码似乎可以正确生成带有 EC 密钥的 PGP 密钥环(如:可以使用 Bouncycastle 解析)。然而,Thunderbird 和 GnuPG 都存在问题。下面是代码,它基于我已经工作的基于 RSA/Elgamal 的实现(为了便于阅读,我只包括了相关的方法):
private static final Provider BOUNCY_CASTLE_PROVIDER = new BouncyCastleProvider();
private static final ASN1ObjectIdentifier CURVE_OID = CryptlibObjectIdentifiers.curvey25519;
private static final int MASTER_KEY_ALGORITHM = ECDSA;
private static final int SUB_KEY_ALGORITHM = ECDH;
private static final int MASTER_KEY_FLAGS = AUTHENTICATION | CERTIFY_OTHER | SIGN_DATA | ENCRYPT_STORAGE | ENCRYPT_COMMS;
private static final int SUB_KEY_FLAGS = ENCRYPT_COMMS | ENCRYPT_STORAGE;
private static final int[] PREFERRED_HASH_ALGORITHMS = {SHA256, SHA1, SHA384, SHA512, SHA224};
private static final int[] PREFERRED_SYMMETRIC_ALGORITHMS = {AES_256, AES_192, AES_128};
public PGPKeyRingGenerator createPGPKeyRingGenerator(String identity, String passphrase, int keySize)
throws PGPException, InvalidAlgorithmParameterException {
PGPKeyPair masterKeyPair = generateEcPgpKeyPair(MASTER_KEY_ALGORITHM);
PGPKeyPair subKeyPair = generateEcPgpKeyPair(SUB_KEY_ALGORITHM);
PGPDigestCalculator sha1Calc = new BcPGPDigestCalculatorProvider().get(SHA1);
PGPDigestCalculator sha256Calc = new BcPGPDigestCalculatorProvider().get(SHA256);
PGPSignatureSubpacketVector masterKeySubPacket = generateMasterkeySubpacket(MASTER_KEY_FLAGS);
PGPSignatureSubpacketVector subKeySubPacket = generateSubkeySubpacket(SUB_KEY_FLAGS);
PGPKeyRingGenerator keyRingGenerator =
new PGPKeyRingGenerator(POSITIVE_CERTIFICATION, masterKeyPair, identity, sha1Calc, masterKeySubPacket,
null,
new JcaPGPContentSignerBuilder(masterKeyPair.getPublicKey().getAlgorithm(), SHA256)
.setProvider(BOUNCY_CASTLE_PROVIDER),
new JcePBESecretKeyEncryptorBuilder(AES_256, sha256Calc)
.setProvider(BOUNCY_CASTLE_PROVIDER)
.build(passphrase.toCharArray()));
keyRingGenerator.addSubKey(subKeyPair, subKeySubPacket, null);
return keyRingGenerator;
}
private AsymmetricCipherKeyPair generateEcKeyPair(ASN1ObjectIdentifier curveOid) {
X9ECParameters curve = CustomNamedCurves.getByOID(curveOid);
ECNamedDomainParameters ecDomainParameters = new ECNamedDomainParameters(curveOid, curve.getCurve(), curve.getG(), curve.getN(), curve.getH(), curve.getSeed());
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
keyPairGenerator.init(new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom()));
return keyPairGenerator.generateKeyPair();
}
private BcPGPKeyPair generateEcPgpKeyPair(int algorithm)
throws InvalidAlgorithmParameterException, PGPException {
return new BcPGPKeyPair(algorithm, generateEcKeyPair(CURVE_OID), new Date());
}
private PGPSignatureSubpacketVector generateMasterkeySubpacket(int keyFlags) {
PGPSignatureSubpacketGenerator subpacketGen = new PGPSignatureSubpacketGenerator();
subpacketGen.setKeyFlags(false, keyFlags);
subpacketGen.setPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
subpacketGen.setPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
return subpacketGen.generate();
}
private PGPSignatureSubpacketVector generateSubkeySubpacket(int keyFlags) {
PGPSignatureSubpacketGenerator subpacketGen = new PGPSignatureSubpacketGenerator();
subpacketGen.setKeyFlags(false, keyFlags);
return subpacketGen.generate();
}
那么,我在这里得到什么以及有什么问题:
- 当我选择 SHA1 作为哈希算法时。对于主密钥,GnuPG 实际上确实读取了密钥环,但子密钥缺少“E”(加密)密钥功能(而且我们得到了关于 SHA1 不足的完全正确的警告):
>> gpg ./ec-sha1.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
gpg: ECDSA key 8DF084241E957FFF requires a 256 bit or larger hash (hash is SHA1)
gpg: ECDSA key 8DF084241E957FFF requires a 256 bit or larger hash (hash is SHA1)
pub cv25519 2021-09-17 [SCA]
553E322AB50692F67E23FE7B8DF084241E957FFF
uid Foo Bar <foo@bar.loc>
sub cv25519 2021-09-17 []
- 使用 SHA256,根本无法解析密钥环:
>> gpg ./ec.asc
gpg: WARNING: no command supplied. Trying to guess what you mean ...
gpg: Fatal: _gcry_mpi_ec_add_points: Montgomery not yet supported
谁能发现代码的问题,以便 GnuPG 和 Thunderbird 都能正确解析密钥环?
【问题讨论】:
标签: java bouncycastle pgp elliptic-curve curve-25519