Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,99 @@ public WithPrimaryKey signOnlyKey()
@Override
public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets)
{
subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS);
subpackets.setKeyFlags(true, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA);
return subpackets;
}
}));
}

/**
* Generate an OpenPGP key based on a single, multipurpose RSA key of the given strength.
* The key will carry a direct-key signature containing default preferences and flags.
* If the passed in userId is non-null, it will be added to the key.
*
* @param bitStrength strength of the RSA key in bits (recommended values: 3072 and above).
* @param userId optional user-id
* @return builder
* @throws PGPException if the key cannot be generated.
*/
public WithPrimaryKey singletonRSAKey(int bitStrength, String userId)
throws PGPException
{
WithPrimaryKey builder = withPrimaryKey(
new KeyPairGeneratorCallback()
{
@Override
public PGPKeyPair generateFrom(PGPKeyPairGenerator generator)
throws PGPException
{
return generator.generateRsaKeyPair(bitStrength);
}
},
SignatureParameters.Callback.Util.modifyHashedSubpackets(
new SignatureSubpacketsFunction()
{
@Override
public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets)
{
subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS);
subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER
| KeyFlags.SIGN_DATA
| KeyFlags.ENCRYPT_STORAGE
| KeyFlags.ENCRYPT_COMMS);
return subpackets;
}
}
)
);

if (userId != null)
{
builder.addUserId(userId);
}

return builder;
}

/**
* Generate an OpenPGP key composed of 3 individual component keys based on RSA of the given strength in bits.
* The primary key will be used to certify third-party keys.
* A subkey is used for signing and a third subkey is used for encryption of messages both for storage and
* communications.
* The primary key will carry a direct-key signature containing default preferences and flags.
* The subkeys will be bound with subkey binding signatures.
* If the passed in userId is non-null, it will be added to the key.
*
* @param bitStrength strength of the keys in bits (recommended values: 3072 and above)
* @param userId optional user-id
* @return builder
* @throws PGPException if the key cannot be generated
*/
public WithPrimaryKey compositeRSAKey(int bitStrength, String userId)
throws PGPException
{
KeyPairGeneratorCallback generatorCallback = new KeyPairGeneratorCallback()
{
@Override
public PGPKeyPair generateFrom(PGPKeyPairGenerator generator)
throws PGPException
{
return generator.generateRsaKeyPair(bitStrength);
}
};

WithPrimaryKey builder = withPrimaryKey(generatorCallback)
.addSigningSubkey(generatorCallback)
.addEncryptionSubkey(generatorCallback);

if (userId != null)
{
builder.addUserId(userId);
}

return builder;
}

/**
* Generate an OpenPGP key with a certification-capable primary key.
* See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ protected void performTestWith(OpenPGPApi api)
testGenerateEd25519x25519Key(api);
testGenerateEd448x448Key(api);

testGenerateSingletonRSAKey(api);
testGenerateCompositeRSAKey(api);

testEnforcesPrimaryOrSubkeyType(api);
testGenerateKeyWithoutSignatures(api);
}
Expand Down Expand Up @@ -320,6 +323,59 @@ private void testGenerateEd448x448Key(OpenPGPApi api)
isEquals(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, hashedSubpackets.getKeyFlags());
}

private void testGenerateSingletonRSAKey(OpenPGPApi api)
throws PGPException
{
Date creationTime = currentTimeRounded();
OpenPGPKeyGenerator generator = api.generateKey(creationTime, false);

OpenPGPKey key = generator.singletonRSAKey(4096, "Alice <alice@example.com>")
.build();

isEquals("Singleton RSA key MUST consist of only a single primary key.", 1, key.getKeys().size());
OpenPGPCertificate.OpenPGPComponentKey primaryKey = key.getPrimaryKey();
isEquals("Primary key MUST be an RSA key", PublicKeyAlgorithmTags.RSA_GENERAL, primaryKey.getAlgorithm());
isEquals("Primary key MUST have a strength of 4096 bits.", 4096, primaryKey.getPGPPublicKey().getBitStrength());

isEquals("The primary key MUST be the certification key", primaryKey, key.getCertificationKeys().get(0));
isEquals("The primary key MUST be the encryption key", primaryKey, key.getEncryptionKeys().get(0));
isEquals("The primary key MUST be the signing key", primaryKey, key.getSigningKeys().get(0));

isNotNull(key.getUserId("Alice <alice@example.com>"));
}

private void testGenerateCompositeRSAKey(OpenPGPApi api)
throws PGPException
{
Date creationTime = currentTimeRounded();
OpenPGPKeyGenerator generator = api.generateKey(creationTime, false);

OpenPGPKey key = generator.compositeRSAKey(4096, "Alice <alice@example.com>")
.build();

isEquals("The composite RSA key MUST consist of 3 component keys", 3, key.getKeys().size());

OpenPGPCertificate.OpenPGPComponentKey primaryKey = key.getPrimaryKey();
isEquals("Primary key MUST be an RSA key", PublicKeyAlgorithmTags.RSA_GENERAL, primaryKey.getAlgorithm());
isEquals("Primary key MUST have a strength of 4096 bits.", 4096, primaryKey.getPGPPublicKey().getBitStrength());
isEquals("There MUST be only one certification key", 1, key.getCertificationKeys().size());
isEquals("The primary key MUST be the certification key", primaryKey, key.getCertificationKeys().get(0));

isEquals("There MUST be only one signing key", 1, key.getSigningKeys().size());
OpenPGPCertificate.OpenPGPComponentKey signingKey = key.getSigningKeys().get(0);
isEquals("Signing key MUST be an RSA key", PublicKeyAlgorithmTags.RSA_GENERAL, signingKey.getAlgorithm());
isEquals("Signing key MUST have a strength of 4096 bits.", 4096, signingKey.getPGPPublicKey().getBitStrength());
isFalse("The signing key MUST NOT be the primary key", primaryKey.equals(signingKey));

isEquals("There MUST be only one encryption key", 1, key.getEncryptionKeys().size());
OpenPGPCertificate.OpenPGPComponentKey encryptionKey = key.getEncryptionKeys().get(0);
isEquals("Primary key MUST be an RSA key", PublicKeyAlgorithmTags.RSA_GENERAL, encryptionKey.getAlgorithm());
isEquals("Encryption key MUST have a strength of 4096 bits.", 4096, encryptionKey.getPGPPublicKey().getBitStrength());
isFalse("The encryption key MUST NOT be the primary key", primaryKey.equals(encryptionKey));

isFalse("The signing key MUST NOT be the encryption key", signingKey.equals(encryptionKey));
}

private void testGenerateCustomKey(OpenPGPApi api)
throws PGPException
{
Expand Down