Skip to content

[PGP v6] Keys generated with BC 1.82 not recognized by OpenPGP.js - "Could not find valid key signature #2229

@Kile2304

Description

@Kile2304

I'm generating PGP v6 keys with BouncyCastle 1.82, but OpenPGP.js v6.3.0 fails to validate the self-signature when trying to use the key for encryption.
Key generation code (Java):

public class PGPKeyPairGenerator {


	public static final int DEFAULT_KEY_SIZE = 			4096;

	public static final int HASH_ALGORITHM = 			HashAlgorithmTags.SHA256;

	public static final int ENCRYPTION_ALGORITHM = 		SymmetricKeyAlgorithmTags.AES_256;

	private static final BigInteger PUBLIC_EXPONENT = 	new BigInteger("65537");

	private static final int CERTAINTY = 				128;

	private static final int PGP_VERSION = 6;

	static {
		BouncyCastleProvider provider = new BouncyCastleProvider();
		String name = provider.getName();
		synchronized (Security.class) {
			Security.removeProvider(name); // remove old instance
			Security.addProvider(provider);
		}
	}

	private String pass_phrase;

	private PGPSecretKey pgp_secret_key;

	public PGPKeyPairGenerator(
		final String user_id
		, final String pass_phrase
	) throws NoSuchAlgorithmException, PGPException {
		this.pass_phrase = pass_phrase;
		PGPKeyPair pgp_key_pair =
			new BcPGPKeyPair(
				PGP_VERSION
				, PGPPublicKey.RSA_GENERAL
				, generate_rsa_key_pair()
				, new Date()
			);

		PGPDigestCalculator digest_calculator = create_digest_calculator();
		this.pgp_secret_key = new PGPSecretKey(
				PGPSignature.DEFAULT_CERTIFICATION
				, pgp_key_pair
				, user_id
				, digest_calculator
				, null
				, null
				, create_content_signer(pgp_key_pair.getPublicKey().getAlgorithm())
				, create_encryptor()
		);
	}

	private PBESecretKeyEncryptor create_encryptor() {
		return
			new JcePBESecretKeyEncryptorBuilder(ENCRYPTION_ALGORITHM)
				.setProvider(BouncyCastleProvider.PROVIDER_NAME)
			.build(pass_phrase.toCharArray());
	}

	private AsymmetricCipherKeyPair generate_rsa_key_pair() {
		RSAKeyPairGenerator generator = new RSAKeyPairGenerator();
		generator.init(
			new RSAKeyGenerationParameters(
				PUBLIC_EXPONENT
				, new SecureRandom()
				, DEFAULT_KEY_SIZE
				, CERTAINTY
			)
		);
		return generator.generateKeyPair();
	}

	private PGPDigestCalculator create_digest_calculator() throws PGPException {
		return new JcaPGPDigestCalculatorProviderBuilder()
				.setProvider(BouncyCastleProvider.PROVIDER_NAME)
			.build()
				.get(HashAlgorithmTags.SHA1);
	}

	private JcaPGPContentSignerBuilder create_content_signer(int algorithm) {
		return new JcaPGPContentSignerBuilder(algorithm, HASH_ALGORITHM)
				.setProvider(BouncyCastleProvider.PROVIDER_NAME);
	}

	public PGPPublicKey getPublicKey() {
		return this.pgp_secret_key.getPublicKey();
	}

	public PGPPrivateKey getPrivateKey() throws PGPException {
		PBESecretKeyDecryptor desc = new JcePBESecretKeyDecryptorBuilder()
				.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(
						this.pass_phrase.toCharArray());
		return this.pgp_secret_key.extractPrivateKey(desc);
	}

	public void getAsciiArmoredPublicKey(OutputStream stream)
			throws IOException {
		ArmoredOutputStream aos_private_key = new ArmoredOutputStream(stream);
		aos_private_key.write(this.pgp_secret_key.getPublicKey().getEncoded());
		aos_private_key.flush();
		aos_private_key.close();
		stream.flush();
	}

	public void getAsciiArmoredPrivateKey(OutputStream stream)
			throws IOException {
		ArmoredOutputStream aosPrivateKey = new ArmoredOutputStream(stream);
		aosPrivateKey.write(this.pgp_secret_key.getEncoded());
		aosPrivateKey.flush();
		aosPrivateKey.close();
		stream.flush();
	}

}

Generated public key (armored):

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: BCPG v1.82

mQIRBmlmYpQBAAACBxAAxrWzjfk5xI597kuUlD20D8wWMlcfq9/++MmWTFWImuOH
BPeqVSIUZDvlLLQ+ICgSqrpnPJUXt1BLNE5VS+XlXs7y1vLuYXOJWPCAyNmjlIs9
vgC3qePkeCxaK3FITggQ0vrMlxet65awAiOJkuNXoqZGYBVKJAcNd41DwPwQ2/cl
ibxGw29W6l/601Qu9Eb4sxtvtILENnwwyo2Dt7fJvgdEQAxO5X9ELhkvZ06g2ILN
XnOEeBxcBHJaO3Pt3l68npX19jqvs9gk0brn3fzCFhdl9uQD+qGoJJB6VUWY9/1D
wM/YHF9CAolIAcCkHGivMca5sIhpp/01EZDY4QBHm5im2RGckUNVfMhmPUygK+v/
NsWwOUXj0hbnkLfDzWxbCX4N8XNbwa+ca0utxRuQurTqXkn6pbxriTfXLmZEdgAY
Kxz7ejf0IZG1rVE/gunxtYrravXG0O1Ml1iTTh8P8RQ8kqs/LFgVrCZBGRsD9n8L
Jdon8u1jNctdxR/XXAwLd6l2dcLrshYlkcagZ4iowfsWziQ4PsezDMG9N2eVH3Wm
ZX4nviii/BmLSBZsVR75l2CdXCdDeoHM9lpJUACJd2TbV2J5hYfDMRWdDJmeC1zN
hq4Wd/2YP7IsPxCjz6uP6vwR0RaTkUXR4yTBZg/XwENweqj0Y2zGCYSwE+GOT/8A
EQEAAbQEY2lhb8LBlwYQAQgAAAA2IqEG5MM9p7wXkr3uSikEIdogobP/SR20Jn3r
2xO5O3KqxKcFgmlmYpQCGw8EFQoJCAQLCQgHAAAAAPSAEKCZP5qxCO5qLkhNBt6M
7wcP/iA+cDnFDzwT4m5LVXrmRlbl/eBcU5CpjzX9FrSGQKXimVgkDl8XPqp4i/q3
Zm+C6QWvVHsMOdGx76jpnxl0J7e3bhNTi6mlmS22oeskfD4VLfdPeewJK4rsurMJ
5c8o8a20KdntMKtC/qhVQBwB5/B1EFScIBxXt8uYYdPsgIL9xhdnuu38kGE/xjpT
NUUFVqrU5bmBA80WAMOUto+I52FxdpJ+AcKV20xGghNlDGPuP9Ae0pzJ1+nzmZkO
wx8rvCSL4eJ3P4ENSuuYaDivw2y1TN61oVMXlu1rFq7/u22WGzijpOcUuka6rjXM
zn9OxVuMY8W/GJQV2lkO8znvpjlL74Eb8wduSBcVzAlgr7QZJvBtCsCzggd+pxgi
x3QCSwQXqQqRVXMSZ5iszvOt4ZklH0FccBpLtk25UeplN5TRD+pV6xe53MzIAlyW
5BzPnlkcS0hwaDhtyxnW0Mv4QghhsEwlEJ+6tM0ey23bTq3ChKP+jpxV6HG7Hs/5
O3SdhC5YcZt8PFJjFb1bipwADdOAAhhfTghjJh1ARl+HN4LecSvhnZsp8Ca5vw2R
seqBH+y3xRjgR9lvP2fhHUO157Jh3auEi0OEM2lSTuU0xp3NDjsKEfcP54FbmuXM
WQnIYvGsj6TpYaOORVagmcFxldaNRj6jr8FC80pmCyjzzqC9
=KoGb
-----END PGP PUBLIC KEY BLOCK-----

Error from OpenPGP.js:
Error: Could not find valid key signature in key e4c33da7bc1792bd

Context:

  • The same code works fine with PGP_VERSION = 4
  • OpenPGP.js v6 claims RFC 9580 (v6) support
  • I also opened an issue on the OpenPGP.js repo: issue

Questions:

  • Has BouncyCastle's PGP v6 implementation been tested for interoperability with other RFC 9580 implementations?
  • Are there any known differences in how BC generates v6 self-signatures compared to the RFC 9580 spec?
  • Is there something missing in my key generation code (e.g., required subpackets for v6 keys)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions