name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.PGPUtilities Maven / Gradle / Ivy
The newest version!
package name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys;
import java.util.Iterator;
import javax.annotation.Nullable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
/**
* FIXME: Cleanup code, throw out duplicates etc
*/
public final class PGPUtilities {
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory
.getLogger(PGPUtilities.class);
// No instances
private PGPUtilities() {
}
/**
* Find secret key.
*
* @param pgpSec the pgp sec
* @param keyID the key id
* @param pass the pass
* @return the decrypted secret key
* @throws PGPException the pGP exception
*/
@SuppressWarnings({"PMD.UseVarargs", "PMD.OnlyOneReturn"})
@Nullable
public static PGPPrivateKey findSecretKey(final PGPSecretKeyRingCollection pgpSec,
final long keyID, final char[] pass)
throws PGPException {
LOGGER.debug("Finding secret key with key ID '0x{}'", Long.toHexString(keyID));
final PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
if (pgpSecKey == null) {
return null;
}
return PGPUtilities.extractPrivateKey(pgpSecKey, pass);
}
/**
* Decrypt an encrypted PGP secret key.
*
* @param encryptedKey An encrypted key
* @param passphrase The passphrase for the key
* @return the decrypted secret key
* @throws PGPException E.g. wrong passphrase
*/
@SuppressWarnings("PMD.UseVarargs")
public static PGPPrivateKey extractPrivateKey(PGPSecretKey encryptedKey, final char[] passphrase)
throws PGPException {
LOGGER.debug("Extracting secret key with key ID '0x{}'",
Long.toHexString(encryptedKey.getKeyID()));
PGPDigestCalculatorProvider calcProvider = new JcaPGPDigestCalculatorProviderBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build();
PBESecretKeyDecryptor decryptor = new JcePBESecretKeyDecryptorBuilder(
calcProvider).setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(passphrase);
return encryptedKey.extractPrivateKey(decryptor);
}
/**
* Extracts the public key with UID {@code publicKeyUid} from key ring collection {@code
* publicKeyRings}.
*
* @param publicKeyUid the public key uid, e.g. [email protected]
* @param publicKeyRings the public key rings
* @return the PGP public key ring containing the userId
* @throws PGPException E.g. multiple keyrings for same uid OR key not found in keyrings
*/
@SuppressWarnings("PMD.LawOfDemeter")
public static PGPPublicKeyRing extractPublicKeyRingForUserId(final String publicKeyUid,
final PGPPublicKeyRingCollection publicKeyRings)
throws PGPException {
if (publicKeyUid == null) {
throw new IllegalArgumentException("publicKeyUid must not be null");
}
if (publicKeyRings == null) {
throw new IllegalArgumentException("publicKeyRings must not be null");
}
// the true parameter indicates, that partial matching of the publicKeyUid is enough.
final Iterator> keyRings = publicKeyRings.getKeyRings("<" + publicKeyUid + ">", true);
PGPPublicKeyRing returnKeyRing = null;
while (keyRings.hasNext()) {
final Object currentKeyRing = keyRings.next();
if (currentKeyRing instanceof PGPPublicKeyRing) {
if (returnKeyRing == null) {
returnKeyRing = (PGPPublicKeyRing) currentKeyRing;
} else {
throw new PGPException("Multiple public key rings found for UID '" + publicKeyUid + "'!");
}
}
}
if (returnKeyRing == null) {
throw new PGPException("No public key ring found for UID '" + publicKeyUid + "'!");
}
LOGGER.debug("Extracted public key ring for UID '{}' with key strength {}.", publicKeyUid,
returnKeyRing
.getPublicKey().getBitStrength()); // NOPMD: LawOfDemeter
return returnKeyRing;
}
/**
* Extract a signing key from the keyring. The implementation tries to find the best matching key.
* . FIXME: refactor this, so that we use all keys from the keyring as valid signing keys .
* Detection of possible signing keys is heuristic at best.
*
* @param keyring search here
* @return a public key that can be used for signing, null if non founf
*/
@SuppressWarnings("PMD.DataflowAnomalyAnalysis")
@Nullable
public static PGPPublicKey extractSigningPublicKey(PGPPublicKeyRing keyring) {
int highestScore = Integer.MIN_VALUE;
PGPPublicKey ret = null;
for (PGPPublicKey pubKey : keyring) {
int score = calculateSigningKeyScore(pubKey);
if (score > highestScore) {
ret = pubKey;
highestScore = score;
}
}
return ret;
}
/*
* Try to find the best signing key.
* - Try not to use master keys (if possible) because signing should be done with subkeys
* - Give a bonus to "sign only" keys (or 'AUTH' only keys - these are not detected)
*/
private static int calculateSigningKeyScore(PGPPublicKey pubKey) {
int score = 0;
if (!pubKey.isMasterKey()) {
score += 100;
}
if (!pubKey.isEncryptionKey()) {
score += 10;
}
return score;
}
/**
* Extracts the first secret signing key for UID {@code signatureUid} suitable for signature
* generation from a key ring collection {@code secretKeyRings}.
*
* @param pgpSec a Collection of secret key rings
* @param signingKeyUid signature Key uid to search for
* @return the first secret key for signatureUid suitable for signatures
* @throws PGPException if no key ring or key with that Uid is found
*/
@SuppressWarnings("PMD.LawOfDemeter")
public static PGPSecretKey extractSecretSigningKeyFromKeyrings(
final PGPSecretKeyRingCollection pgpSec, final String signingKeyUid)
throws PGPException {
int highestScore = Integer.MIN_VALUE;
PGPSecretKey key = null;
final Iterator ringIterator = pgpSec
.getKeyRings("<" + signingKeyUid + ">", true);
while (ringIterator.hasNext()) {
final PGPSecretKeyRing kRing = ringIterator.next();
final Iterator secretKeyIterator = kRing.getSecretKeys();
while (secretKeyIterator.hasNext()) {
final PGPSecretKey secretKey = secretKeyIterator.next();
int score = calculateSigningKeyScore(secretKey.getPublicKey());
if (secretKey.isSigningKey() && (score > highestScore)) {
key = secretKey;
highestScore = score;
}
}
}
if (key == null) {
throw new PGPException(
String.format("Can't find signing key for uid '%s' in key ring.", signingKeyUid));
}
LOGGER.trace("Extracted secret signing key for UID '{}'.", signingKeyUid);
return key;
}
/**
* Returns the 'best' encryption key encountered in {@code publicKeyRing}.
*
* @param publicKeyRing the public key ring
* @return the encryption key
*/
@Nullable
public static PGPPublicKey getEncryptionKey(final PGPPublicKeyRing publicKeyRing) {
int score;
int highestScore = Integer.MIN_VALUE;
PGPPublicKey returnKey = null;
for (PGPPublicKey pubKey : publicKeyRing) {
score = calculateEncryptionKeyScore(pubKey);
if (score > highestScore) {
returnKey = pubKey;
highestScore = score;
}
}
return returnKey;
}
/*
* Try to find the best encryption key.
* - Try not to use master keys (if possible) because encryption should be done with subkeys
*/
@SuppressWarnings("PMD.OnlyOneReturn")
private static int calculateEncryptionKeyScore(PGPPublicKey pubKey) {
if (!pubKey.isEncryptionKey()) {
return Integer.MIN_VALUE;
}
int score = 0;
if (!pubKey.isMasterKey()) {
score++;
}
return score;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy