mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-23 11:27:57 +01:00
Work on KeyRingInfo
This commit is contained in:
parent
6cb9091b2a
commit
909f0e7be3
4 changed files with 224 additions and 72 deletions
|
@ -15,10 +15,12 @@
|
|||
*/
|
||||
package org.pgpainless.encryption_signing;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -32,15 +34,46 @@ import org.pgpainless.key.SubkeyIdentifier;
|
|||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
|
||||
/**
|
||||
* Options for the encryption process.
|
||||
* This class can be used to set encryption parameters, like encryption keys and passphrases, algorithms etc.
|
||||
*
|
||||
* A typical use might look like follows:
|
||||
* <pre>
|
||||
* {@code
|
||||
* EncryptionOptions opt = new EncryptionOptions();
|
||||
* opt.addRecipient(aliceKey, "Alice <alice@wonderland.lit>");
|
||||
* opt.addPassphrase(Passphrase.fromPassword("AdditionalDecryptionPassphrase123"));
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* To use a custom symmetric encryption algorithm, use {@link #overrideEncryptionAlgorithm(SymmetricKeyAlgorithm)}.
|
||||
* This will cause PGPainless to use the provided algorithm for message encryption, instead of negotiating an algorithm
|
||||
* by inspecting the provided recipient keys.
|
||||
*
|
||||
* By default, PGPainless will only encrypt to a single encryption capable subkey per recipient key.
|
||||
* This behavior can be changed, eg. by calling
|
||||
* <pre>
|
||||
* {@code
|
||||
* opt.addRecipient(aliceKey, EncryptionOptions.encryptToAllCapableSubkeys());
|
||||
* }
|
||||
* </pre>
|
||||
* when adding the recipient key.
|
||||
*/
|
||||
public class EncryptionOptions {
|
||||
|
||||
private final EncryptionStream.Purpose purpose;
|
||||
private final Set<PGPKeyEncryptionMethodGenerator> encryptionMethods = new LinkedHashSet<>();
|
||||
private final Set<SubkeyIdentifier> encryptionKeys = new LinkedHashSet<>();
|
||||
private final Map<SubkeyIdentifier, KeyRingInfo> keyRingInfo = new HashMap<>();
|
||||
private final EncryptionKeySelector encryptionKeySelector = encryptToFirstSubkey();
|
||||
|
||||
private SymmetricKeyAlgorithm encryptionAlgorithmOverride = null;
|
||||
|
||||
/**
|
||||
* Encrypt to keys both carrying the key flag {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_COMMS}
|
||||
* or {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_STORAGE}.
|
||||
*/
|
||||
public EncryptionOptions() {
|
||||
this(EncryptionStream.Purpose.STORAGE_AND_COMMUNICATIONS);
|
||||
}
|
||||
|
@ -49,10 +82,22 @@ public class EncryptionOptions {
|
|||
this.purpose = purpose;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create an {@link EncryptionOptions} object which will encrypt for keys
|
||||
* which carry the flag {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_COMMS}.
|
||||
*
|
||||
* @return encryption options
|
||||
*/
|
||||
public static EncryptionOptions encryptCommunications() {
|
||||
return new EncryptionOptions(EncryptionStream.Purpose.COMMUNICATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create an {@link EncryptionOptions} object which will encrypt for keys
|
||||
* which carry the flag {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_STORAGE}.
|
||||
*
|
||||
* @return encryption options
|
||||
*/
|
||||
public static EncryptionOptions encryptDataAtRest() {
|
||||
return new EncryptionOptions(EncryptionStream.Purpose.STORAGE);
|
||||
}
|
||||
|
@ -64,14 +109,32 @@ public class EncryptionOptions {
|
|||
* @param key key ring
|
||||
* @param userId user id
|
||||
*/
|
||||
public void addRecipient(PGPPublicKeyRing key, String userId) {
|
||||
public EncryptionOptions addRecipient(PGPPublicKeyRing key, String userId) {
|
||||
return addRecipient(key, userId, encryptionKeySelector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a recipient by providing a key and recipient user-id, as well as a strategy for selecting one or multiple
|
||||
* encryption capable subkeys from the key.
|
||||
*
|
||||
* @param key key
|
||||
* @param userId user-id
|
||||
* @param encryptionKeySelectionStrategy strategy to select one or more encryption subkeys to encrypt to
|
||||
*/
|
||||
public EncryptionOptions addRecipient(PGPPublicKeyRing key, String userId, EncryptionKeySelector encryptionKeySelectionStrategy) {
|
||||
KeyRingInfo info = new KeyRingInfo(key, new Date());
|
||||
|
||||
PGPPublicKey encryptionSubkey = info.getEncryptionSubkey(userId, purpose);
|
||||
if (encryptionSubkey == null) {
|
||||
throw new AssertionError("Key has no encryption subkey.");
|
||||
List<PGPPublicKey> encryptionSubkeys = encryptionKeySelectionStrategy
|
||||
.selectEncryptionSubkeys(info.getEncryptionSubkeys(userId, purpose));
|
||||
if (encryptionSubkeys.isEmpty()) {
|
||||
throw new AssertionError("Key has no suitable encryption subkeys.");
|
||||
}
|
||||
addRecipientKey(key, encryptionSubkey);
|
||||
|
||||
for (PGPPublicKey encryptionSubkey : encryptionSubkeys) {
|
||||
addRecipientKey(key, encryptionSubkey);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,13 +142,30 @@ public class EncryptionOptions {
|
|||
*
|
||||
* @param key key ring
|
||||
*/
|
||||
public void addRecipient(PGPPublicKeyRing key) {
|
||||
public EncryptionOptions addRecipient(PGPPublicKeyRing key) {
|
||||
return addRecipient(key, encryptionKeySelector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a recipient by providing a key and an encryption key selection strategy.
|
||||
*
|
||||
* @param key key ring
|
||||
* @param encryptionKeySelectionStrategy strategy used to select one or multiple encryption subkeys.
|
||||
*/
|
||||
public EncryptionOptions addRecipient(PGPPublicKeyRing key, EncryptionKeySelector encryptionKeySelectionStrategy) {
|
||||
KeyRingInfo info = new KeyRingInfo(key, new Date());
|
||||
PGPPublicKey encryptionSubkey = info.getEncryptionSubkey(purpose);
|
||||
if (encryptionSubkey == null) {
|
||||
throw new IllegalArgumentException("Key has no encryption subkey.");
|
||||
|
||||
List<PGPPublicKey> encryptionSubkeys = encryptionKeySelectionStrategy
|
||||
.selectEncryptionSubkeys(info.getEncryptionSubkeys(purpose));
|
||||
if (encryptionSubkeys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Key has no suitable encryption subkeys.");
|
||||
}
|
||||
addRecipientKey(key, encryptionSubkey);
|
||||
|
||||
for (PGPPublicKey encryptionSubkey : encryptionSubkeys) {
|
||||
addRecipientKey(key, encryptionSubkey);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addRecipientKey(PGPPublicKeyRing keyRing, PGPPublicKey key) {
|
||||
|
@ -100,13 +180,13 @@ public class EncryptionOptions {
|
|||
*
|
||||
* @param passphrase passphrase
|
||||
*/
|
||||
public void addPassphrase(Passphrase passphrase) {
|
||||
public EncryptionOptions addPassphrase(Passphrase passphrase) {
|
||||
if (passphrase.isEmpty()) {
|
||||
throw new IllegalArgumentException("Passphrase must not be empty.");
|
||||
}
|
||||
PBEKeyEncryptionMethodGenerator encryptionMethod = ImplementationFactory
|
||||
.getInstance().getPBEKeyEncryptionMethodGenerator(passphrase);
|
||||
addEncryptionMethod(encryptionMethod);
|
||||
return addEncryptionMethod(encryptionMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,8 +199,9 @@ public class EncryptionOptions {
|
|||
*
|
||||
* @param encryptionMethod encryption method
|
||||
*/
|
||||
public void addEncryptionMethod(PGPKeyEncryptionMethodGenerator encryptionMethod) {
|
||||
public EncryptionOptions addEncryptionMethod(PGPKeyEncryptionMethodGenerator encryptionMethod) {
|
||||
encryptionMethods.add(encryptionMethod);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<PGPKeyEncryptionMethodGenerator> getEncryptionMethods() {
|
||||
|
@ -141,4 +222,38 @@ public class EncryptionOptions {
|
|||
}
|
||||
this.encryptionAlgorithmOverride = encryptionAlgorithm;
|
||||
}
|
||||
|
||||
public interface EncryptionKeySelector {
|
||||
List<PGPPublicKey> selectEncryptionSubkeys(List<PGPPublicKey> encryptionCapableKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only encrypt to the first valid encryption capable subkey we stumble upon.
|
||||
*
|
||||
* @return encryption key selector
|
||||
*/
|
||||
public static EncryptionKeySelector encryptToFirstSubkey() {
|
||||
return new EncryptionKeySelector() {
|
||||
@Override
|
||||
public List<PGPPublicKey> selectEncryptionSubkeys(List<PGPPublicKey> encryptionCapableKeys) {
|
||||
return encryptionCapableKeys.isEmpty() ? Collections.emptyList() : Collections.singletonList(encryptionCapableKeys.get(0));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt to any valid, encryption capable subkey on the key ring.
|
||||
*
|
||||
* @return encryption key selector
|
||||
*/
|
||||
public static EncryptionKeySelector encryptToAllCapableSubkeys() {
|
||||
return new EncryptionKeySelector() {
|
||||
@Override
|
||||
public List<PGPPublicKey> selectEncryptionSubkeys(List<PGPPublicKey> encryptionCapableKeys) {
|
||||
return encryptionCapableKeys;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Create encryptToBestSubkey() method
|
||||
}
|
||||
|
|
|
@ -82,18 +82,21 @@ public final class SigningOptions {
|
|||
KeyRingInfo keyRingInfo = new KeyRingInfo(secretKey, new Date());
|
||||
if (userId != null) {
|
||||
if (!keyRingInfo.isUserIdValid(userId)) {
|
||||
throw new KeyValidationException(userId, keyRingInfo.getCurrentUserIdCertification(userId), keyRingInfo.getUserIdRevocation(userId));
|
||||
throw new KeyValidationException(userId, keyRingInfo.getLatestUserIdCertification(userId), keyRingInfo.getUserIdRevocation(userId));
|
||||
}
|
||||
}
|
||||
|
||||
PGPPublicKey signingPubKey = keyRingInfo.getSigningSubkey();
|
||||
if (signingPubKey == null) {
|
||||
List<PGPPublicKey> signingPubKeys = keyRingInfo.getSigningSubkeys();
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw new AssertionError("Key has no valid signing key.");
|
||||
}
|
||||
PGPSecretKey signingSecKey = secretKey.getSecretKey(signingPubKey.getKeyID());
|
||||
PGPPrivateKey signingSubkey = signingSecKey.extractPrivateKey(secretKeyDecryptor.getDecryptor(signingPubKey.getKeyID()));
|
||||
List<HashAlgorithm> hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(userId, signingPubKey.getKeyID());
|
||||
addSigningMethod(secretKey, signingSubkey, hashAlgorithms.get(0), signatureType, false);
|
||||
|
||||
for (PGPPublicKey signingPubKey : signingPubKeys) {
|
||||
PGPSecretKey signingSecKey = secretKey.getSecretKey(signingPubKey.getKeyID());
|
||||
PGPPrivateKey signingSubkey = signingSecKey.extractPrivateKey(secretKeyDecryptor.getDecryptor(signingPubKey.getKeyID()));
|
||||
List<HashAlgorithm> hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(userId, signingPubKey.getKeyID());
|
||||
addSigningMethod(secretKey, signingSubkey, hashAlgorithms.get(0), signatureType, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void addDetachedSignature(SecretKeyRingProtector secretKeyDecryptor,
|
||||
|
@ -111,18 +114,21 @@ public final class SigningOptions {
|
|||
KeyRingInfo keyRingInfo = new KeyRingInfo(secretKey, new Date());
|
||||
if (userId != null) {
|
||||
if (!keyRingInfo.isUserIdValid(userId)) {
|
||||
throw new KeyValidationException(userId, keyRingInfo.getCurrentUserIdCertification(userId), keyRingInfo.getUserIdRevocation(userId));
|
||||
throw new KeyValidationException(userId, keyRingInfo.getLatestUserIdCertification(userId), keyRingInfo.getUserIdRevocation(userId));
|
||||
}
|
||||
}
|
||||
|
||||
PGPPublicKey signingPubKey = keyRingInfo.getSigningSubkey();
|
||||
if (signingPubKey == null) {
|
||||
List<PGPPublicKey> signingPubKeys = keyRingInfo.getSigningSubkeys();
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw new AssertionError("Key has no valid signing key.");
|
||||
}
|
||||
PGPSecretKey signingSecKey = secretKey.getSecretKey(signingPubKey.getKeyID());
|
||||
PGPPrivateKey signingSubkey = signingSecKey.extractPrivateKey(secretKeyDecryptor.getDecryptor(signingPubKey.getKeyID()));
|
||||
List<HashAlgorithm> hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(userId, signingPubKey.getKeyID());
|
||||
addSigningMethod(secretKey, signingSubkey, hashAlgorithms.get(0), signatureType, true);
|
||||
|
||||
for (PGPPublicKey signingPubKey : signingPubKeys) {
|
||||
PGPSecretKey signingSecKey = secretKey.getSecretKey(signingPubKey.getKeyID());
|
||||
PGPPrivateKey signingSubkey = signingSecKey.extractPrivateKey(secretKeyDecryptor.getDecryptor(signingPubKey.getKeyID()));
|
||||
List<HashAlgorithm> hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(userId, signingPubKey.getKeyID());
|
||||
addSigningMethod(secretKey, signingSubkey, hashAlgorithms.get(0), signatureType, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSigningMethod(PGPSecretKeyRing secretKey,
|
||||
|
|
|
@ -29,7 +29,6 @@ import java.util.Set;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bouncycastle.bcpg.sig.KeyFlags;
|
||||
import org.bouncycastle.bcpg.sig.PrimaryUserID;
|
||||
import org.bouncycastle.openpgp.PGPKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
|
@ -116,7 +115,7 @@ public class KeyRingInfo {
|
|||
* @return public key or null
|
||||
*/
|
||||
public PGPPublicKey getPublicKey(long keyId) {
|
||||
return keys.getPublicKey(keyId);
|
||||
return getPublicKey(keys, keyId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,12 +142,36 @@ public class KeyRingInfo {
|
|||
}
|
||||
|
||||
if (publicKey == getPublicKey()) {
|
||||
if (signatures.primaryKeyRevocation != null) {
|
||||
if (SignatureUtils.isHardRevocation(signatures.primaryKeyRevocation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return signatures.primaryKeyRevocation == null;
|
||||
}
|
||||
|
||||
PGPSignature binding = signatures.subkeyBindings.get(keyId);
|
||||
PGPSignature revocation = signatures.subkeyRevocations.get(keyId);
|
||||
return binding != null && revocation == null;
|
||||
|
||||
// No valid binding
|
||||
if (binding == null || SignatureUtils.isSignatureExpired(binding)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Revocation
|
||||
if (revocation != null) {
|
||||
if (SignatureUtils.isHardRevocation(revocation)) {
|
||||
// Subkey is hard revoked
|
||||
return false;
|
||||
} else {
|
||||
if (!SignatureUtils.isSignatureExpired(revocation) && revocation.getCreationTime().after(binding.getCreationTime())) {
|
||||
// Key is soft-revoked, not yet re-bound
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -322,11 +345,13 @@ public class KeyRingInfo {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the current direct-key self signature.
|
||||
* Return the latest direct-key self signature.
|
||||
*
|
||||
* @return
|
||||
* Note: This signature might be expired (check with {@link SignatureUtils#isSignatureExpired(PGPSignature)}).
|
||||
*
|
||||
* @return latest direct key self-signature
|
||||
*/
|
||||
public PGPSignature getCurrentDirectKeySelfSignature() {
|
||||
public PGPSignature getLatestDirectKeySelfSignature() {
|
||||
return signatures.primaryKeySelfSignature;
|
||||
}
|
||||
|
||||
|
@ -334,7 +359,7 @@ public class KeyRingInfo {
|
|||
return signatures.primaryKeyRevocation;
|
||||
}
|
||||
|
||||
public PGPSignature getCurrentUserIdCertification(String userId) {
|
||||
public PGPSignature getLatestUserIdCertification(String userId) {
|
||||
return signatures.userIdCertifications.get(userId);
|
||||
}
|
||||
|
||||
|
@ -353,27 +378,28 @@ public class KeyRingInfo {
|
|||
public List<KeyFlag> getKeyFlagsOf(long keyId) {
|
||||
if (getPublicKey().getKeyID() == keyId) {
|
||||
|
||||
PGPSignature directKeySignature = getCurrentDirectKeySelfSignature();
|
||||
PGPSignature directKeySignature = getLatestDirectKeySelfSignature();
|
||||
if (directKeySignature != null) {
|
||||
KeyFlags flags = SignatureSubpacketsUtil.getKeyFlags(directKeySignature);
|
||||
if (flags != null) {
|
||||
return KeyFlag.fromBitmask(flags.getFlags());
|
||||
List<KeyFlag> keyFlags = SignatureSubpacketsUtil.parseKeyFlags(directKeySignature);
|
||||
if (keyFlags != null) {
|
||||
return keyFlags;
|
||||
}
|
||||
}
|
||||
|
||||
String primaryUserId = getPrimaryUserId();
|
||||
if (primaryUserId != null) {
|
||||
KeyFlags flags = SignatureSubpacketsUtil.getKeyFlags(getCurrentUserIdCertification(primaryUserId));
|
||||
if (flags != null) {
|
||||
return KeyFlag.fromBitmask(flags.getFlags());
|
||||
PGPSignature userIdSignature = getLatestUserIdCertification(primaryUserId);
|
||||
List<KeyFlag> keyFlags = SignatureSubpacketsUtil.parseKeyFlags(userIdSignature);
|
||||
if (keyFlags != null) {
|
||||
return keyFlags;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PGPSignature bindingSignature = getCurrentSubkeyBindingSignature(keyId);
|
||||
if (bindingSignature != null) {
|
||||
KeyFlags flags = SignatureSubpacketsUtil.getKeyFlags(bindingSignature);
|
||||
if (flags != null) {
|
||||
return KeyFlag.fromBitmask(flags.getFlags());
|
||||
List<KeyFlag> keyFlags = SignatureSubpacketsUtil.parseKeyFlags(bindingSignature);
|
||||
if (keyFlags != null) {
|
||||
return keyFlags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -385,14 +411,14 @@ public class KeyRingInfo {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
PGPSignature userIdCertification = getCurrentUserIdCertification(userId);
|
||||
PGPSignature userIdCertification = getLatestUserIdCertification(userId);
|
||||
if (userIdCertification == null) {
|
||||
return Collections.emptyList();
|
||||
throw new AssertionError("While user-id '" + userId + "' was reported as valid, there appears to be no certification for it.");
|
||||
}
|
||||
|
||||
KeyFlags keyFlags = SignatureSubpacketsUtil.getKeyFlags(userIdCertification);
|
||||
List<KeyFlag> keyFlags = SignatureSubpacketsUtil.parseKeyFlags(userIdCertification);
|
||||
if (keyFlags != null) {
|
||||
return KeyFlag.fromBitmask(keyFlags.getFlags());
|
||||
return keyFlags;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
@ -428,7 +454,7 @@ public class KeyRingInfo {
|
|||
|
||||
private PGPSignature getMostRecentSignature() {
|
||||
Set<PGPSignature> allSignatures = new HashSet<>();
|
||||
PGPSignature mostRecentSelfSignature = getCurrentDirectKeySelfSignature();
|
||||
PGPSignature mostRecentSelfSignature = getLatestDirectKeySelfSignature();
|
||||
PGPSignature revocationSelfSignature = getRevocationSelfSignature();
|
||||
if (mostRecentSelfSignature != null) allSignatures.add(mostRecentSelfSignature);
|
||||
if (revocationSelfSignature != null) allSignatures.add(revocationSelfSignature);
|
||||
|
@ -462,12 +488,12 @@ public class KeyRingInfo {
|
|||
*/
|
||||
public Date getPrimaryKeyExpirationDate() {
|
||||
Date lastExpiration = null;
|
||||
if (getCurrentDirectKeySelfSignature() != null) {
|
||||
lastExpiration = SignatureUtils.getKeyExpirationDate(getCreationDate(), getCurrentDirectKeySelfSignature());
|
||||
if (getLatestDirectKeySelfSignature() != null) {
|
||||
lastExpiration = SignatureUtils.getKeyExpirationDate(getCreationDate(), getLatestDirectKeySelfSignature());
|
||||
}
|
||||
|
||||
for (String userId : getValidUserIds()) {
|
||||
PGPSignature signature = getCurrentUserIdCertification(userId);
|
||||
PGPSignature signature = getLatestUserIdCertification(userId);
|
||||
Date expiration = SignatureUtils.getKeyExpirationDate(getCreationDate(), signature);
|
||||
if (expiration != null && (lastExpiration == null || expiration.after(lastExpiration))) {
|
||||
lastExpiration = expiration;
|
||||
|
@ -543,8 +569,9 @@ public class KeyRingInfo {
|
|||
return false;
|
||||
}
|
||||
|
||||
public PGPPublicKey getEncryptionSubkey(EncryptionStream.Purpose purpose) {
|
||||
public List<PGPPublicKey> getEncryptionSubkeys(EncryptionStream.Purpose purpose) {
|
||||
Iterator<PGPPublicKey> subkeys = keys.getPublicKeys();
|
||||
List<PGPPublicKey> encryptionKeys = new ArrayList<>();
|
||||
while (subkeys.hasNext()) {
|
||||
PGPPublicKey subKey = subkeys.next();
|
||||
|
||||
|
@ -560,36 +587,37 @@ public class KeyRingInfo {
|
|||
switch (purpose) {
|
||||
case COMMUNICATIONS:
|
||||
if (keyFlags.contains(KeyFlag.ENCRYPT_COMMS)) {
|
||||
return subKey;
|
||||
encryptionKeys.add(subKey);
|
||||
}
|
||||
break;
|
||||
case STORAGE:
|
||||
if (keyFlags.contains(KeyFlag.ENCRYPT_STORAGE)) {
|
||||
return subKey;
|
||||
encryptionKeys.add(subKey);
|
||||
}
|
||||
break;
|
||||
case STORAGE_AND_COMMUNICATIONS:
|
||||
if (keyFlags.contains(KeyFlag.ENCRYPT_COMMS) || keyFlags.contains(KeyFlag.ENCRYPT_STORAGE)) {
|
||||
return subKey;
|
||||
encryptionKeys.add(subKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return encryptionKeys;
|
||||
}
|
||||
|
||||
public PGPPublicKey getEncryptionSubkey(String userId, EncryptionStream.Purpose purpose) {
|
||||
public List<PGPPublicKey> getEncryptionSubkeys(String userId, EncryptionStream.Purpose purpose) {
|
||||
if (userId != null) {
|
||||
if (!isUserIdValid(userId)) {
|
||||
throw new KeyValidationException(userId, getCurrentUserIdCertification(userId), getUserIdRevocation(userId));
|
||||
throw new KeyValidationException(userId, getLatestUserIdCertification(userId), getUserIdRevocation(userId));
|
||||
}
|
||||
}
|
||||
|
||||
return getEncryptionSubkey(purpose);
|
||||
return getEncryptionSubkeys(purpose);
|
||||
}
|
||||
|
||||
public PGPPublicKey getSigningSubkey() {
|
||||
public List<PGPPublicKey> getSigningSubkeys() {
|
||||
Iterator<PGPPublicKey> subkeys = keys.getPublicKeys();
|
||||
List<PGPPublicKey> signingKeys = new ArrayList<>();
|
||||
while (subkeys.hasNext()) {
|
||||
PGPPublicKey subKey = subkeys.next();
|
||||
|
||||
|
@ -599,16 +627,16 @@ public class KeyRingInfo {
|
|||
|
||||
List<KeyFlag> keyFlags = getKeyFlagsOf(subKey.getKeyID());
|
||||
if (keyFlags.contains(KeyFlag.SIGN_DATA)) {
|
||||
return subKey;
|
||||
signingKeys.add(subKey);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return signingKeys;
|
||||
}
|
||||
|
||||
public List<HashAlgorithm> getPreferredHashAlgorithms(String userId, long keyID) {
|
||||
PGPSignature signature = getCurrentUserIdCertification(userId == null ? getPrimaryUserId() : userId);
|
||||
PGPSignature signature = getLatestUserIdCertification(userId == null ? getPrimaryUserId() : userId);
|
||||
if (signature == null) {
|
||||
signature = getCurrentDirectKeySelfSignature();
|
||||
signature = getLatestDirectKeySelfSignature();
|
||||
}
|
||||
if (signature == null) {
|
||||
signature = getCurrentSubkeyBindingSignature(keyID);
|
||||
|
|
|
@ -26,11 +26,12 @@ import org.bouncycastle.openpgp.PGPException;
|
|||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.encryption_signing.EncryptionOptions;
|
||||
import org.pgpainless.encryption_signing.EncryptionResult;
|
||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||
import org.pgpainless.encryption_signing.ProducerOptions;
|
||||
import org.pgpainless.key.WeirdKeys;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
|
||||
|
@ -46,23 +47,25 @@ public class TestTwoSubkeysEncryption {
|
|||
* {@link WeirdKeys#TWO_CRYPT_SUBKEYS} is a key that has two subkeys which both carry the key flags
|
||||
* {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_COMMS} and {@link org.pgpainless.algorithm.KeyFlag#ENCRYPT_STORAGE}.
|
||||
*
|
||||
* This test makes sure that both subkeys are used for encryption.
|
||||
* This test verifies that {@link EncryptionOptions#addRecipient(PGPPublicKeyRing, EncryptionOptions.EncryptionKeySelector)}
|
||||
* works properly, if {@link EncryptionOptions#encryptToAllCapableSubkeys()} is provided as argument.
|
||||
*
|
||||
* @throws IOException not expected
|
||||
* @throws PGPException not expected
|
||||
*/
|
||||
@Test
|
||||
@Disabled("We may not want to encrypt to all enc capable subkeys.")
|
||||
public void testEncryptsToBothSubkeys() throws IOException, PGPException {
|
||||
PGPSecretKeyRing twoSuitableSubkeysKeyRing = WeirdKeys.getTwoCryptSubkeysKey();
|
||||
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(twoSuitableSubkeysKeyRing);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign(EncryptionStream.Purpose.STORAGE)
|
||||
.onOutputStream(out)
|
||||
.toRecipient(publicKeys)
|
||||
.and()
|
||||
.doNotSign()
|
||||
.noArmor();
|
||||
.withOptions(
|
||||
ProducerOptions.encrypt(new EncryptionOptions(EncryptionStream.Purpose.STORAGE_AND_COMMUNICATIONS)
|
||||
.addRecipient(publicKeys, EncryptionOptions.encryptToAllCapableSubkeys())
|
||||
)
|
||||
.setAsciiArmor(false)
|
||||
);
|
||||
|
||||
Streams.pipeAll(getPlainIn(), encryptionStream);
|
||||
encryptionStream.close();
|
||||
|
|
Loading…
Reference in a new issue