mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-23 12:52:07 +01:00
Increase test coverage by writing bunch of JUnit tests
This commit is contained in:
parent
ee1f90e850
commit
bec2fb5ce1
15 changed files with 457 additions and 190 deletions
|
@ -40,7 +40,7 @@ public class CallbackBasedKeyringProtector implements SecretKeyRingProtector2 {
|
||||||
@Override
|
@Override
|
||||||
public PBESecretKeyDecryptor getDecryptor(PGPSecretKey key) throws PGPException {
|
public PBESecretKeyDecryptor getDecryptor(PGPSecretKey key) throws PGPException {
|
||||||
Passphrase passphrase = lookupPassphraseInCache(key);
|
Passphrase passphrase = lookupPassphraseInCache(key);
|
||||||
if (passphrase != null) {
|
if (passphrase == null) {
|
||||||
passphrase = callback.getPassphraseFor(key);
|
passphrase = callback.getPassphraseFor(key);
|
||||||
passphraseCache.put(key.getKeyID(), passphrase);
|
passphraseCache.put(key.getKeyID(), passphrase);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,9 @@ public class PassphraseMapKeyRingProtector implements SecretKeyRingProtector, Se
|
||||||
public Passphrase getPassphraseFor(Long keyId) {
|
public Passphrase getPassphraseFor(Long keyId) {
|
||||||
Passphrase passphrase = cache.get(keyId);
|
Passphrase passphrase = cache.get(keyId);
|
||||||
if (passphrase == null || !passphrase.isValid()) {
|
if (passphrase == null || !passphrase.isValid()) {
|
||||||
|
if (provider == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
passphrase = provider.getPassphraseFor(keyId);
|
passphrase = provider.getPassphraseFor(keyId);
|
||||||
if (passphrase != null) {
|
if (passphrase != null) {
|
||||||
cache.put(keyId, passphrase);
|
cache.put(keyId, passphrase);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package org.pgpainless.key.protection;
|
package org.pgpainless.key.protection;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
@ -52,7 +53,11 @@ public interface SecretKeyRingProtector {
|
||||||
@Nullable PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException;
|
@Nullable PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException;
|
||||||
|
|
||||||
static SecretKeyRingProtector unlockAllKeysWith(Passphrase passphrase, PGPSecretKeyRing keys) {
|
static SecretKeyRingProtector unlockAllKeysWith(Passphrase passphrase, PGPSecretKeyRing keys) {
|
||||||
return PasswordBasedSecretKeyRingProtector.forKey(keys, passphrase);
|
Map<Long, Passphrase> map = new ConcurrentHashMap<>();
|
||||||
|
for (PGPSecretKey secretKey : keys) {
|
||||||
|
map.put(secretKey.getKeyID(), passphrase);
|
||||||
|
}
|
||||||
|
return fromPassphraseMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SecretKeyRingProtector unlockSingleKeyWith(Passphrase passphrase, PGPSecretKey key) {
|
static SecretKeyRingProtector unlockSingleKeyWith(Passphrase passphrase, PGPSecretKey key) {
|
||||||
|
|
|
@ -24,12 +24,12 @@ import java.util.logging.Logger;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
|
import org.pgpainless.implementation.ImplementationFactory;
|
||||||
import org.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
import org.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
||||||
|
|
||||||
public class SignedByMasterKey {
|
public class KeyBelongsToKeyRing {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(SignedByMasterKey.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(KeyBelongsToKeyRing.class.getName());
|
||||||
|
|
||||||
public static class PubkeySelectionStrategy extends PublicKeySelectionStrategy {
|
public static class PubkeySelectionStrategy extends PublicKeySelectionStrategy {
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class SignedByMasterKey {
|
||||||
PGPSignature signature = signatures.next();
|
PGPSignature signature = signatures.next();
|
||||||
if (signature.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
if (signature.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
||||||
try {
|
try {
|
||||||
signature.init(new BcPGPContentVerifierBuilderProvider(), masterKey);
|
signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), masterKey);
|
||||||
return signature.verifyCertification(masterKey, key);
|
return signature.verifyCertification(masterKey, key);
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
LOGGER.log(Level.WARNING, "Could not verify subkey signature of key " +
|
LOGGER.log(Level.WARNING, "Could not verify subkey signature of key " +
|
|
@ -42,7 +42,7 @@ import org.bouncycastle.util.io.Streams;
|
||||||
import org.pgpainless.algorithm.KeyFlag;
|
import org.pgpainless.algorithm.KeyFlag;
|
||||||
import org.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
import org.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
||||||
import org.pgpainless.key.selection.key.impl.NoRevocation;
|
import org.pgpainless.key.selection.key.impl.NoRevocation;
|
||||||
import org.pgpainless.key.selection.key.impl.SignedByMasterKey;
|
import org.pgpainless.key.selection.key.impl.KeyBelongsToKeyRing;
|
||||||
import org.pgpainless.key.selection.key.util.And;
|
import org.pgpainless.key.selection.key.util.And;
|
||||||
|
|
||||||
public class BCUtil {
|
public class BCUtil {
|
||||||
|
@ -136,7 +136,7 @@ public class BCUtil {
|
||||||
}
|
}
|
||||||
// Only select keys which are signed by the master key and not revoked.
|
// Only select keys which are signed by the master key and not revoked.
|
||||||
PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy(
|
PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy(
|
||||||
new SignedByMasterKey.PubkeySelectionStrategy(masterKey),
|
new KeyBelongsToKeyRing.PubkeySelectionStrategy(masterKey),
|
||||||
new NoRevocation.PubKeySelectionStrategy());
|
new NoRevocation.PubKeySelectionStrategy());
|
||||||
|
|
||||||
PGPPublicKeyRing cleaned = ring;
|
PGPPublicKeyRing cleaned = ring;
|
||||||
|
@ -167,7 +167,7 @@ public class BCUtil {
|
||||||
}
|
}
|
||||||
// Only select keys which are signed by the master key and not revoked.
|
// Only select keys which are signed by the master key and not revoked.
|
||||||
PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy(
|
PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy(
|
||||||
new SignedByMasterKey.PubkeySelectionStrategy(masterKey),
|
new KeyBelongsToKeyRing.PubkeySelectionStrategy(masterKey),
|
||||||
new NoRevocation.PubKeySelectionStrategy());
|
new NoRevocation.PubKeySelectionStrategy());
|
||||||
|
|
||||||
PGPSecretKeyRing cleaned = ring;
|
PGPSecretKeyRing cleaned = ring;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020 Paul Schaub.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.pgpainless.util;
|
|
||||||
|
|
||||||
public class NotYetImplementedException extends AssertionError {
|
|
||||||
|
|
||||||
}
|
|
|
@ -110,4 +110,27 @@ public class Passphrase {
|
||||||
public static Passphrase emptyPassphrase() {
|
public static Passphrase emptyPassphrase() {
|
||||||
return new Passphrase(null);
|
return new Passphrase(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
if (getChars() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return new String(getChars()).hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof Passphrase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Passphrase other = (Passphrase) obj;
|
||||||
|
return Arrays.equals(getChars(), other.getChars());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2021 Paul Schaub.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.pgpainless.util;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bouncycastle.bcpg.sig.Features;
|
|
||||||
import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint;
|
|
||||||
import org.bouncycastle.bcpg.sig.NotationData;
|
|
||||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
|
||||||
import org.pgpainless.algorithm.KeyFlag;
|
|
||||||
import org.pgpainless.algorithm.SignatureSubpacket;
|
|
||||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|
||||||
|
|
||||||
public class SubpacketsInspector {
|
|
||||||
|
|
||||||
public static StringBuilder toString(PGPSignatureSubpacketVector vector) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
optAppendSignatureCreationTime(sb, vector);
|
|
||||||
optAppendSignatureExpirationTime(sb, vector);
|
|
||||||
optAppendFlags(sb, vector);
|
|
||||||
optAppendFeatures(sb, vector);
|
|
||||||
optAppendIssuerKeyID(sb, vector);
|
|
||||||
optAppendSignerUserID(sb, vector);
|
|
||||||
optAppendKeyExpirationTime(sb, vector);
|
|
||||||
optAppendIntendedRecipientFingerprint(sb, vector);
|
|
||||||
optAppendNotationDataOccurrences(sb, vector);
|
|
||||||
optAppendCriticalTags(sb, vector);
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendCriticalTags(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
int[] criticalTagCodes = v.getCriticalTags();
|
|
||||||
if (criticalTagCodes.length == 0) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append("Critical Tags: ").append('[');
|
|
||||||
for (int i = 0; i < criticalTagCodes.length; i++) {
|
|
||||||
int tag = criticalTagCodes[i];
|
|
||||||
try {
|
|
||||||
sb.append(SignatureSubpacket.fromCode(tag)).append(i == criticalTagCodes.length - 1 ? "" : ", ");
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.append(']').append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendNotationDataOccurrences(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
NotationData[] notationData = v.getNotationDataOccurrences();
|
|
||||||
if (notationData.length == 0) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
sb.append("Notation Data: [").append('\n');
|
|
||||||
for (int i = 0; i < notationData.length; i++) {
|
|
||||||
NotationData n = notationData[i];
|
|
||||||
sb.append('\'').append(n.getNotationName())
|
|
||||||
.append("' = '").append(n.getNotationValue())
|
|
||||||
.append(i == notationData.length - 1 ? "'" : "', ");
|
|
||||||
}
|
|
||||||
return sb.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendSignatureCreationTime(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
return sb.append("Sig created: ").append(v.getSignatureCreationTime()).append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendSignatureExpirationTime(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
long time = v.getSignatureExpirationTime();
|
|
||||||
sb.append("Sig expires: ");
|
|
||||||
if (time == 0) {
|
|
||||||
sb.append("never");
|
|
||||||
} else {
|
|
||||||
Date creationTime = v.getSignatureCreationTime();
|
|
||||||
if (creationTime != null) {
|
|
||||||
long seconds = creationTime.getTime() / 1000;
|
|
||||||
Date expirationDate = new Date((seconds + time) * 1000);
|
|
||||||
sb.append(expirationDate).append(" (").append(time).append(')');
|
|
||||||
} else {
|
|
||||||
sb.append(time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendFlags(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
List<KeyFlag> flagList = KeyFlag.fromBitmask(v.getKeyFlags());
|
|
||||||
sb.append("Flags: ").append(Arrays.toString(flagList.toArray())).append('\n');
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendFeatures(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
Features features = v.getFeatures();
|
|
||||||
if (features == null) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
sb.append("Features: ");
|
|
||||||
sb.append('[');
|
|
||||||
if (features.supportsModificationDetection()) {
|
|
||||||
sb.append("Modification Detection");
|
|
||||||
}
|
|
||||||
sb.append(']');
|
|
||||||
return sb.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendIssuerKeyID(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
long keyId = v.getIssuerKeyID();
|
|
||||||
if (keyId == 0) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
return sb.append("Issuer KeyID: ").append(Long.toHexString(keyId)).append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendSignerUserID(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
String userID = v.getSignerUserID();
|
|
||||||
if (userID == null) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
return sb.append("Signer UserID: ").append(userID).append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendKeyExpirationTime(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
long expirationTime = v.getKeyExpirationTime();
|
|
||||||
sb.append("Key Expiration Time: ");
|
|
||||||
if (expirationTime == 0) {
|
|
||||||
sb.append("never");
|
|
||||||
} else {
|
|
||||||
sb.append(expirationTime).append(" seconds after creation");
|
|
||||||
}
|
|
||||||
return sb.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static StringBuilder optAppendIntendedRecipientFingerprint(StringBuilder sb, PGPSignatureSubpacketVector v) {
|
|
||||||
IntendedRecipientFingerprint fingerprint = v.getIntendedRecipientFingerprint();
|
|
||||||
if (fingerprint == null) {
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
return sb.append("Intended Recipient Fingerprint: ")
|
|
||||||
.append(new OpenPgpV4Fingerprint(fingerprint.getFingerprint()))
|
|
||||||
.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -105,9 +105,20 @@ public class KeyRingInfoTest {
|
||||||
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys);
|
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys);
|
||||||
|
|
||||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||||
assertEquals(secretKeys.getSecretKey(), info.getSecretKey());
|
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys), info.getSecretKey());
|
||||||
|
|
||||||
info = PGPainless.inspectKeyRing(publicKeys);
|
info = PGPainless.inspectKeyRing(publicKeys);
|
||||||
assertNull(info.getSecretKey());
|
assertNull(info.getSecretKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetPublicKey() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||||
|
|
||||||
|
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||||
|
assertEquals(KeyRingUtils.requirePrimaryPublicKeyFrom(secretKeys), info.getPublicKey());
|
||||||
|
|
||||||
|
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys),
|
||||||
|
KeyRingUtils.requireSecretKeyFrom(secretKeys, secretKeys.getPublicKey().getKeyID()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,6 @@ public class UserIdRevocationTest {
|
||||||
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
|
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
|
||||||
.withDescription("I lost my mail password"))
|
.withDescription("I lost my mail password"))
|
||||||
.done();
|
.done();
|
||||||
PGPSignature s = PGPainless.inspectKeyRing(secretKeys).getLatestValidSelfSignatureOnKey();
|
|
||||||
PGPSignature signature = SignatureUtils.getLatestSelfSignatureForUserId(secretKeys.getPublicKey(), "secondary@key.id");
|
PGPSignature signature = SignatureUtils.getLatestSelfSignatureForUserId(secretKeys.getPublicKey(), "secondary@key.id");
|
||||||
RevocationReason reason = (RevocationReason) signature.getHashedSubPackets()
|
RevocationReason reason = (RevocationReason) signature.getHashedSubPackets()
|
||||||
.getSubpacket(SignatureSubpacketTags.REVOCATION_REASON);
|
.getSubpacket(SignatureSubpacketTags.REVOCATION_REASON);
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.protection;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
import org.pgpainless.key.protection.passphrase_provider.MapBasedPassphraseProvider;
|
||||||
|
import org.pgpainless.util.Passphrase;
|
||||||
|
|
||||||
|
public class MapBasedPassphraseProviderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapBasedProvider() throws IOException, PGPException {
|
||||||
|
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
|
||||||
|
passphraseMap.put(1L, Passphrase.fromPassword("tiger"));
|
||||||
|
passphraseMap.put(123123123L, Passphrase.fromPassword("snake"));
|
||||||
|
passphraseMap.put(69696969L, Passphrase.emptyPassphrase());
|
||||||
|
MapBasedPassphraseProvider provider = new MapBasedPassphraseProvider(passphraseMap);
|
||||||
|
|
||||||
|
assertEquals(Passphrase.fromPassword("tiger"), provider.getPassphraseFor(1L));
|
||||||
|
assertEquals(Passphrase.fromPassword("snake"), provider.getPassphraseFor(123123123L));
|
||||||
|
assertEquals(Passphrase.emptyPassphrase(), provider.getPassphraseFor(69696969L));
|
||||||
|
assertNull(provider.getPassphraseFor(555L));
|
||||||
|
|
||||||
|
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||||
|
passphraseMap = new ConcurrentHashMap<>();
|
||||||
|
passphraseMap.put(secretKeys.getSecretKey().getKeyID(), TestKeys.CRYPTIE_PASSPHRASE);
|
||||||
|
provider = new MapBasedPassphraseProvider(passphraseMap);
|
||||||
|
|
||||||
|
assertEquals(TestKeys.CRYPTIE_PASSPHRASE, provider.getPassphraseFor(secretKeys.getSecretKey()));
|
||||||
|
assertNull(provider.getPassphraseFor(TestKeys.getEmilSecretKeyRing().getSecretKey()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.protection;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider;
|
||||||
|
import org.pgpainless.util.Passphrase;
|
||||||
|
|
||||||
|
public class SecretKeyRingProtectorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnlockAllKeysWithSamePassword() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
|
||||||
|
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||||
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAllKeysWith(TestKeys.CRYPTIE_PASSPHRASE, secretKeys);
|
||||||
|
for (PGPSecretKey secretKey : secretKeys) {
|
||||||
|
PBESecretKeyDecryptor decryptor = protector.getDecryptor(secretKey.getKeyID());
|
||||||
|
assertNotNull(decryptor);
|
||||||
|
secretKey.extractPrivateKey(decryptor);
|
||||||
|
}
|
||||||
|
PGPSecretKeyRing unrelatedKeys = PGPainless.generateKeyRing().simpleEcKeyRing("unrelated",
|
||||||
|
"SecurePassword");
|
||||||
|
for (PGPSecretKey unrelatedKey : unrelatedKeys) {
|
||||||
|
PBESecretKeyDecryptor decryptor = protector.getDecryptor(unrelatedKey.getKeyID());
|
||||||
|
assertNull(decryptor);
|
||||||
|
assertThrows(PGPException.class, () -> unrelatedKey.extractPrivateKey(protector.getDecryptor(unrelatedKey.getKeyID())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnprotectedKeys() throws PGPException {
|
||||||
|
Random random = new Random();
|
||||||
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Long keyId = random.nextLong();
|
||||||
|
assertNull(protector.getEncryptor(keyId));
|
||||||
|
assertNull(protector.getDecryptor(keyId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUnlockSingleKeyWithPassphrase() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||||
|
Iterator<PGPSecretKey> iterator = secretKeys.iterator();
|
||||||
|
PGPSecretKey secretKey = iterator.next();
|
||||||
|
PGPSecretKey subKey = iterator.next();
|
||||||
|
|
||||||
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockSingleKeyWith(TestKeys.CRYPTIE_PASSPHRASE, secretKey);
|
||||||
|
assertNotNull(protector.getDecryptor(secretKey.getKeyID()));
|
||||||
|
assertNotNull(protector.getEncryptor(secretKey.getKeyID()));
|
||||||
|
assertNull(protector.getEncryptor(subKey.getKeyID()));
|
||||||
|
assertNull(protector.getDecryptor(subKey.getKeyID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromPassphraseMap() {
|
||||||
|
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
|
||||||
|
passphraseMap.put(1L, Passphrase.emptyPassphrase());
|
||||||
|
PassphraseMapKeyRingProtector protector = (PassphraseMapKeyRingProtector) SecretKeyRingProtector.fromPassphraseMap(passphraseMap);
|
||||||
|
|
||||||
|
assertNotNull(protector.getPassphraseFor(1L));
|
||||||
|
assertNull(protector.getPassphraseFor(5L));
|
||||||
|
|
||||||
|
protector.addPassphrase(5L, Passphrase.fromPassword("pa55w0rd"));
|
||||||
|
protector.forgetPassphrase(1L);
|
||||||
|
|
||||||
|
assertNull(protector.getPassphraseFor(1L));
|
||||||
|
assertNotNull(protector.getPassphraseFor(5L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMissingPassphraseCallback() {
|
||||||
|
Map<Long, Passphrase> passphraseMap = new ConcurrentHashMap<>();
|
||||||
|
passphraseMap.put(1L, Passphrase.emptyPassphrase());
|
||||||
|
PassphraseMapKeyRingProtector protector = new PassphraseMapKeyRingProtector(passphraseMap,
|
||||||
|
KeyRingProtectionSettings.secureDefaultSettings(), new SecretKeyPassphraseProvider() {
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Passphrase getPassphraseFor(Long keyId) {
|
||||||
|
return Passphrase.fromPassword("missingP455w0rd");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assertEquals(Passphrase.emptyPassphrase(), protector.getPassphraseFor(1L));
|
||||||
|
assertEquals(Passphrase.fromPassword("missingP455w0rd"), protector.getPassphraseFor(3L));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallbackBasedKeyRingProtector() throws IOException, PGPException {
|
||||||
|
SecretKeyRingProtector2 protector = new CallbackBasedKeyringProtector(new CallbackBasedKeyringProtector.Callback() {
|
||||||
|
@Override
|
||||||
|
public Passphrase getPassphraseFor(PGPSecretKey secretKey) {
|
||||||
|
return TestKeys.CRYPTIE_PASSPHRASE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||||
|
for (PGPSecretKey secretKey : secretKeys) {
|
||||||
|
secretKey.extractPrivateKey(protector.getDecryptor(secretKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.selection.key;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.algorithm.KeyFlag;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
import org.pgpainless.key.selection.key.impl.EncryptionKeySelectionStrategy;
|
||||||
|
import org.pgpainless.key.selection.key.impl.HasAnyKeyFlagSelectionStrategy;
|
||||||
|
import org.pgpainless.key.selection.key.util.Or;
|
||||||
|
|
||||||
|
public class AndOrSelectionStrategyTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOr() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing ring = TestKeys.getEmilSecretKeyRing();
|
||||||
|
Iterator<PGPSecretKey> secretKeys = ring.getSecretKeys();
|
||||||
|
Or.SecKeySelectionStrategy secStrategy = new Or.SecKeySelectionStrategy(
|
||||||
|
new HasAnyKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_COMMS),
|
||||||
|
new HasAnyKeyFlagSelectionStrategy.SecretKey(KeyFlag.ENCRYPT_STORAGE)
|
||||||
|
);
|
||||||
|
PGPSecretKey certSecKey = secretKeys.next();
|
||||||
|
PGPSecretKey cryptSecKey = secretKeys.next();
|
||||||
|
|
||||||
|
assertFalse(secStrategy.accept(certSecKey));
|
||||||
|
assertTrue(secStrategy.accept(cryptSecKey));
|
||||||
|
|
||||||
|
Iterator<PGPPublicKey> publicKeys = ring.getPublicKeys();
|
||||||
|
Or.PubKeySelectionStrategy pubStrategy = new Or.PubKeySelectionStrategy(
|
||||||
|
new EncryptionKeySelectionStrategy(KeyFlag.ENCRYPT_COMMS),
|
||||||
|
new EncryptionKeySelectionStrategy(KeyFlag.ENCRYPT_STORAGE)
|
||||||
|
);
|
||||||
|
PGPPublicKey certPubKey = publicKeys.next();
|
||||||
|
PGPPublicKey cryptPubKey = publicKeys.next();
|
||||||
|
|
||||||
|
assertFalse(pubStrategy.accept(certPubKey));
|
||||||
|
assertTrue(pubStrategy.accept(cryptPubKey));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.selection.key;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
import org.pgpainless.key.selection.key.impl.KeyBelongsToKeyRing;
|
||||||
|
|
||||||
|
public class KeyBelongsToKeyRingTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStrategyOnlyAcceptsKeysThatBelongToKeyRing() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("test@test.test");
|
||||||
|
Iterator<PGPPublicKey> iterator = secretKeys.getPublicKeys();
|
||||||
|
PGPPublicKey primaryKey = iterator.next();
|
||||||
|
PGPPublicKey subKey = iterator.next();
|
||||||
|
|
||||||
|
KeyBelongsToKeyRing.PubkeySelectionStrategy strategy = new KeyBelongsToKeyRing.PubkeySelectionStrategy(primaryKey);
|
||||||
|
assertTrue(strategy.accept(primaryKey));
|
||||||
|
assertTrue(strategy.accept(subKey));
|
||||||
|
|
||||||
|
PGPSecretKeyRing unrelatedKeys = TestKeys.getEmilSecretKeyRing();
|
||||||
|
Iterator<PGPPublicKey> unrelated = unrelatedKeys.getPublicKeys();
|
||||||
|
while (unrelated.hasNext()) {
|
||||||
|
PGPPublicKey unrelatedKey = unrelated.next();
|
||||||
|
assertFalse(strategy.accept(unrelatedKey));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 Paul Schaub.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.selection.keyring;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.key.TestKeys;
|
||||||
|
import org.pgpainless.key.selection.keyring.impl.ExactUserId;
|
||||||
|
import org.pgpainless.util.MultiMap;
|
||||||
|
|
||||||
|
public class KeyRingsFromCollectionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectSecretKeyRingFromSecretKeyRingCollectionTest() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing emil = TestKeys.getEmilSecretKeyRing();
|
||||||
|
PGPSecretKeyRing juliet = TestKeys.getJulietSecretKeyRing();
|
||||||
|
PGPSecretKeyRingCollection collection = new PGPSecretKeyRingCollection(Arrays.asList(emil, juliet));
|
||||||
|
|
||||||
|
SecretKeyRingSelectionStrategy<String> strategy = new ExactUserId.SecRingSelectionStrategy();
|
||||||
|
Set<PGPSecretKeyRing> secretKeyRings = strategy.selectKeyRingsFromCollection(TestKeys.JULIET_UID, collection);
|
||||||
|
assertEquals(1, secretKeyRings.size());
|
||||||
|
assertEquals(juliet.getPublicKey().getKeyID(), secretKeyRings.iterator().next().getPublicKey().getKeyID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectSecretKeyRingMapFromSecretKeyRingCollectionMapTest() throws IOException, PGPException {
|
||||||
|
PGPSecretKeyRing emil = TestKeys.getEmilSecretKeyRing();
|
||||||
|
PGPSecretKeyRing juliet = TestKeys.getJulietSecretKeyRing();
|
||||||
|
MultiMap<String, PGPSecretKeyRingCollection> map = new MultiMap<>();
|
||||||
|
PGPSecretKeyRingCollection julietCollection = new PGPSecretKeyRingCollection(Arrays.asList(emil, juliet));
|
||||||
|
map.put(TestKeys.JULIET_UID, julietCollection);
|
||||||
|
PGPSecretKeyRingCollection emilCollection = new PGPSecretKeyRingCollection(Collections.singletonList(emil));
|
||||||
|
map.put(TestKeys.EMIL_UID, emilCollection);
|
||||||
|
assertEquals(2, julietCollection.size());
|
||||||
|
map.put("invalidId", emilCollection);
|
||||||
|
|
||||||
|
SecretKeyRingSelectionStrategy<String> strategy = new ExactUserId.SecRingSelectionStrategy();
|
||||||
|
MultiMap<String, PGPSecretKeyRing> selected = strategy.selectKeyRingsFromCollections(map);
|
||||||
|
assertEquals(1, selected.get(TestKeys.JULIET_UID).size());
|
||||||
|
assertEquals(1, selected.get(TestKeys.EMIL_UID).size());
|
||||||
|
assertNull(selected.get("invalidId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectPublicKeyRingFromPublicKeyRingCollectionTest() throws IOException, PGPException {
|
||||||
|
PGPPublicKeyRing emil = TestKeys.getEmilPublicKeyRing();
|
||||||
|
PGPPublicKeyRing juliet = TestKeys.getJulietPublicKeyRing();
|
||||||
|
PGPPublicKeyRingCollection collection = new PGPPublicKeyRingCollection(Arrays.asList(emil, juliet));
|
||||||
|
|
||||||
|
PublicKeyRingSelectionStrategy<String> strategy = new ExactUserId.PubRingSelectionStrategy();
|
||||||
|
Set<PGPPublicKeyRing> publicKeyRings = strategy.selectKeyRingsFromCollection(TestKeys.JULIET_UID, collection);
|
||||||
|
assertEquals(1, publicKeyRings.size());
|
||||||
|
assertEquals(juliet.getPublicKey().getKeyID(), publicKeyRings.iterator().next().getPublicKey().getKeyID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectPublicKeyRingMapFromPublicKeyRingCollectionMapTest() throws IOException, PGPException {
|
||||||
|
PGPPublicKeyRing emil = TestKeys.getEmilPublicKeyRing();
|
||||||
|
PGPPublicKeyRing juliet = TestKeys.getJulietPublicKeyRing();
|
||||||
|
MultiMap<String, PGPPublicKeyRingCollection> map = new MultiMap<>();
|
||||||
|
PGPPublicKeyRingCollection julietCollection = new PGPPublicKeyRingCollection(Arrays.asList(emil, juliet));
|
||||||
|
map.put(TestKeys.JULIET_UID, julietCollection);
|
||||||
|
PGPPublicKeyRingCollection emilCollection = new PGPPublicKeyRingCollection(Collections.singletonList(emil));
|
||||||
|
map.put(TestKeys.EMIL_UID, emilCollection);
|
||||||
|
assertEquals(2, julietCollection.size());
|
||||||
|
map.put("invalidId", emilCollection);
|
||||||
|
|
||||||
|
PublicKeyRingSelectionStrategy<String> strategy = new ExactUserId.PubRingSelectionStrategy();
|
||||||
|
MultiMap<String, PGPPublicKeyRing> selected = strategy.selectKeyRingsFromCollections(map);
|
||||||
|
assertEquals(1, selected.get(TestKeys.JULIET_UID).size());
|
||||||
|
assertEquals(1, selected.get(TestKeys.EMIL_UID).size());
|
||||||
|
assertNull(selected.get("invalidId"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue