mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-18 02:12:06 +01:00
Still WiP, add selection strategies
This commit is contained in:
parent
2ba0200047
commit
8a2ae0a989
28 changed files with 977 additions and 108 deletions
|
@ -15,21 +15,16 @@ import java.util.Collections;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.encryption_signing.SecretKeyRingDecryptor;
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
|
import de.vanitasvitae.crypto.pgpainless.key.generation.type.length.RsaLength;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPObjectFactory;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
|
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
|
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
|
||||||
import org.bouncycastle.util.encoders.Base64;
|
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
|
@ -43,7 +38,7 @@ public class Main {
|
||||||
PGPSecretKeyRing a = PGPainless.generateKeyRing().simpleRsaKeyRing("a@b.c", RsaLength._2048);
|
PGPSecretKeyRing a = PGPainless.generateKeyRing().simpleRsaKeyRing("a@b.c", RsaLength._2048);
|
||||||
PGPSecretKeyRing b = PGPainless.generateKeyRing().simpleRsaKeyRing("b@c.d", RsaLength._2048);
|
PGPSecretKeyRing b = PGPainless.generateKeyRing().simpleRsaKeyRing("b@c.d", RsaLength._2048);
|
||||||
|
|
||||||
SecretKeyRingDecryptor secretKeyRingDecryptor = new SecretKeyRingDecryptor() {
|
SecretKeyRingProtector secretKeyRingDecryptor = new SecretKeyRingProtector() {
|
||||||
@Override
|
@Override
|
||||||
public PBESecretKeyDecryptor getDecryptor(Long keyId) {
|
public PBESecretKeyDecryptor getDecryptor(Long keyId) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -62,7 +57,7 @@ public class Main {
|
||||||
OutputStream encryptor = PGPainless.createEncryptor().onOutputStream(toEncrypted)
|
OutputStream encryptor = PGPainless.createEncryptor().onOutputStream(toEncrypted)
|
||||||
.toRecipient(b.getPublicKey())
|
.toRecipient(b.getPublicKey())
|
||||||
.usingAlgorithms(SymmetricKeyAlgorithm.AES_256, HashAlgorithm.SHA512, CompressionAlgorithm.UNCOMPRESSED)
|
.usingAlgorithms(SymmetricKeyAlgorithm.AES_256, HashAlgorithm.SHA512, CompressionAlgorithm.UNCOMPRESSED)
|
||||||
.signWith(a.getSecretKey(), secretKeyRingDecryptor)
|
.signWith(a, secretKeyRingDecryptor)
|
||||||
.asciiArmor();
|
.asciiArmor();
|
||||||
|
|
||||||
Streams.pipeAll(fromPlain, encryptor);
|
Streams.pipeAll(fromPlain, encryptor);
|
||||||
|
@ -94,7 +89,7 @@ public class Main {
|
||||||
System.out.println(new String(toPlain.toByteArray()));
|
System.out.println(new String(toPlain.toByteArray()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void gpg(PGPSecretKeyRing a, PGPSecretKeyRing b, SecretKeyRingDecryptor secretKeyRingDecryptor)
|
private static void gpg(PGPSecretKeyRing a, PGPSecretKeyRing b, SecretKeyRingProtector secretKeyRingDecryptor)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
String gpg = "-----BEGIN PGP MESSAGE-----\n" +
|
String gpg = "-----BEGIN PGP MESSAGE-----\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
@ -132,7 +127,7 @@ public class Main {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void symm(PGPSecretKeyRing a, PGPSecretKeyRing b, SecretKeyRingDecryptor secretKeyRingDecryptor)
|
public static void symm(PGPSecretKeyRing a, PGPSecretKeyRing b, SecretKeyRingProtector secretKeyRingDecryptor)
|
||||||
throws IOException, PGPException {
|
throws IOException, PGPException {
|
||||||
byte[] bytes = "Diese Nachricht ist streng geheim!!!".getBytes(Charset.forName("UTF-8"));
|
byte[] bytes = "Diese Nachricht ist streng geheim!!!".getBytes(Charset.forName("UTF-8"));
|
||||||
ByteArrayInputStream fromPlain = new ByteArrayInputStream(bytes);
|
ByteArrayInputStream fromPlain = new ByteArrayInputStream(bytes);
|
||||||
|
@ -142,7 +137,7 @@ public class Main {
|
||||||
.onOutputStream(toEncrypted)
|
.onOutputStream(toEncrypted)
|
||||||
.toRecipient(b.getPublicKey())
|
.toRecipient(b.getPublicKey())
|
||||||
.usingAlgorithms(SymmetricKeyAlgorithm.AES_256, HashAlgorithm.SHA512, CompressionAlgorithm.UNCOMPRESSED)
|
.usingAlgorithms(SymmetricKeyAlgorithm.AES_256, HashAlgorithm.SHA512, CompressionAlgorithm.UNCOMPRESSED)
|
||||||
.signWith(a.getSecretKey(), secretKeyRingDecryptor)
|
.signWith(a, secretKeyRingDecryptor)
|
||||||
.noArmor();
|
.noArmor();
|
||||||
|
|
||||||
Streams.pipeAll(fromPlain, encryptor);
|
Streams.pipeAll(fromPlain, encryptor);
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
package de.vanitasvitae.crypto.pgpainless;
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
|
||||||
public class PublicKeyNotFoundException extends Exception {
|
public class PublicKeyNotFoundException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final long keyId;
|
private long keyId;
|
||||||
|
|
||||||
public PublicKeyNotFoundException(long keyId) {
|
public PublicKeyNotFoundException(long keyId) {
|
||||||
super("No PGPPublicKey with id " + Long.toHexString(keyId) + " (" + keyId + ") found.");
|
super("No PGPPublicKey with id " + Long.toHexString(keyId) + " (" + keyId + ") found.");
|
||||||
this.keyId = keyId;
|
this.keyId = keyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PublicKeyNotFoundException(PGPException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public long getKeyId() {
|
public long getKeyId() {
|
||||||
return keyId;
|
return keyId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ public class SecretKeyNotFoundException extends Exception {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final long keyId;
|
private long keyId;
|
||||||
|
|
||||||
public SecretKeyNotFoundException(long keyId) {
|
public SecretKeyNotFoundException(long keyId) {
|
||||||
super("No PGPSecretKey with id " + Long.toHexString(keyId) + " (" + keyId + ") found.");
|
super("No PGPSecretKey with id " + Long.toHexString(keyId) + " (" + keyId + ") found.");
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import de.vanitasvitae.crypto.pgpainless.PainlessResult;
|
import de.vanitasvitae.crypto.pgpainless.PainlessResult;
|
||||||
import de.vanitasvitae.crypto.pgpainless.encryption_signing.SecretKeyRingDecryptor;
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
@ -17,7 +17,7 @@ public class DecryptionBuilder implements DecryptionBuilderInterface {
|
||||||
|
|
||||||
private InputStream inputStream;
|
private InputStream inputStream;
|
||||||
private PGPSecretKeyRingCollection decryptionKeys;
|
private PGPSecretKeyRingCollection decryptionKeys;
|
||||||
private SecretKeyRingDecryptor decryptionKeyDecryptor;
|
private SecretKeyRingProtector decryptionKeyDecryptor;
|
||||||
private Set<PGPPublicKeyRing> verificationKeys = new HashSet<>();
|
private Set<PGPPublicKeyRing> verificationKeys = new HashSet<>();
|
||||||
private Set<Long> trustedKeyIds = new HashSet<>();
|
private Set<Long> trustedKeyIds = new HashSet<>();
|
||||||
private MissingPublicKeyCallback missingPublicKeyCallback = null;
|
private MissingPublicKeyCallback missingPublicKeyCallback = null;
|
||||||
|
@ -31,7 +31,7 @@ public class DecryptionBuilder implements DecryptionBuilderInterface {
|
||||||
class DecryptWithImpl implements DecryptWith {
|
class DecryptWithImpl implements DecryptWith {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VerifyWith decryptWith(PGPSecretKeyRingCollection secretKeyRings, SecretKeyRingDecryptor decryptor) {
|
public VerifyWith decryptWith(PGPSecretKeyRingCollection secretKeyRings, SecretKeyRingProtector decryptor) {
|
||||||
DecryptionBuilder.this.decryptionKeys = secretKeyRings;
|
DecryptionBuilder.this.decryptionKeys = secretKeyRings;
|
||||||
DecryptionBuilder.this.decryptionKeyDecryptor = decryptor;
|
DecryptionBuilder.this.decryptionKeyDecryptor = decryptor;
|
||||||
return new VerifyWithImpl();
|
return new VerifyWithImpl();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import java.io.InputStream;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import de.vanitasvitae.crypto.pgpainless.PainlessResult;
|
import de.vanitasvitae.crypto.pgpainless.PainlessResult;
|
||||||
import de.vanitasvitae.crypto.pgpainless.encryption_signing.SecretKeyRingDecryptor;
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
@ -17,7 +17,7 @@ public interface DecryptionBuilderInterface {
|
||||||
|
|
||||||
interface DecryptWith {
|
interface DecryptWith {
|
||||||
|
|
||||||
VerifyWith decryptWith(PGPSecretKeyRingCollection secretKeyRings, SecretKeyRingDecryptor decryptor);
|
VerifyWith decryptWith(PGPSecretKeyRingCollection secretKeyRings, SecretKeyRingProtector decryptor);
|
||||||
|
|
||||||
VerifyWith doNotDecrypt();
|
VerifyWith doNotDecrypt();
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import de.vanitasvitae.crypto.pgpainless.PainlessResult;
|
||||||
import de.vanitasvitae.crypto.pgpainless.PainlessStream;
|
import de.vanitasvitae.crypto.pgpainless.PainlessStream;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.encryption_signing.SecretKeyRingDecryptor;
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import org.bouncycastle.openpgp.PGPCompressedData;
|
import org.bouncycastle.openpgp.PGPCompressedData;
|
||||||
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
import org.bouncycastle.openpgp.PGPEncryptedDataList;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
@ -40,7 +40,7 @@ public class InputStreamFactory {
|
||||||
private InputStream inputStream;
|
private InputStream inputStream;
|
||||||
|
|
||||||
private final PGPSecretKeyRingCollection decryptionKeys;
|
private final PGPSecretKeyRingCollection decryptionKeys;
|
||||||
private final SecretKeyRingDecryptor decryptionKeyDecryptor;
|
private final SecretKeyRingProtector decryptionKeyDecryptor;
|
||||||
private final Set<PGPPublicKeyRing> verificationKeys = new HashSet<>();
|
private final Set<PGPPublicKeyRing> verificationKeys = new HashSet<>();
|
||||||
private final Set<Long> trustedKeyIds = new HashSet<>();
|
private final Set<Long> trustedKeyIds = new HashSet<>();
|
||||||
private final MissingPublicKeyCallback missingPublicKeyCallback;
|
private final MissingPublicKeyCallback missingPublicKeyCallback;
|
||||||
|
@ -50,7 +50,7 @@ public class InputStreamFactory {
|
||||||
private final Map<Long, PGPOnePassSignature> verifiableOnePassSignatures = new HashMap<>();
|
private final Map<Long, PGPOnePassSignature> verifiableOnePassSignatures = new HashMap<>();
|
||||||
|
|
||||||
private InputStreamFactory(PGPSecretKeyRingCollection decryptionKeys,
|
private InputStreamFactory(PGPSecretKeyRingCollection decryptionKeys,
|
||||||
SecretKeyRingDecryptor decryptor,
|
SecretKeyRingProtector decryptor,
|
||||||
Set<PGPPublicKeyRing> verificationKeys,
|
Set<PGPPublicKeyRing> verificationKeys,
|
||||||
Set<Long> trustedKeyIds,
|
Set<Long> trustedKeyIds,
|
||||||
MissingPublicKeyCallback missingPublicKeyCallback)
|
MissingPublicKeyCallback missingPublicKeyCallback)
|
||||||
|
@ -64,7 +64,7 @@ public class InputStreamFactory {
|
||||||
|
|
||||||
public static PainlessResult.ResultAndInputStream create(InputStream inputStream,
|
public static PainlessResult.ResultAndInputStream create(InputStream inputStream,
|
||||||
PGPSecretKeyRingCollection decryptionKeys,
|
PGPSecretKeyRingCollection decryptionKeys,
|
||||||
SecretKeyRingDecryptor decryptor,
|
SecretKeyRingProtector decryptor,
|
||||||
Set<PGPPublicKeyRing> verificationKeys,
|
Set<PGPPublicKeyRing> verificationKeys,
|
||||||
Set<Long> trustedKeyIds,
|
Set<Long> trustedKeyIds,
|
||||||
MissingPublicKeyCallback missingPublicKeyCallback)
|
MissingPublicKeyCallback missingPublicKeyCallback)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package de.vanitasvitae.crypto.pgpainless.encryption_signing;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -11,6 +12,7 @@ import de.vanitasvitae.crypto.pgpainless.SecretKeyNotFoundException;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
@ -25,7 +27,7 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
|
||||||
private OutputStream outputStream;
|
private OutputStream outputStream;
|
||||||
private final Set<PGPPublicKey> encryptionKeys = new HashSet<>();
|
private final Set<PGPPublicKey> encryptionKeys = new HashSet<>();
|
||||||
private final Set<PGPSecretKey> signingKeys = new HashSet<>();
|
private final Set<PGPSecretKey> signingKeys = new HashSet<>();
|
||||||
private SecretKeyRingDecryptor signingKeysDecryptor;
|
private SecretKeyRingProtector signingKeysDecryptor;
|
||||||
private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_128;
|
private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_128;
|
||||||
private HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
|
private HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
|
||||||
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED;
|
private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED;
|
||||||
|
@ -41,52 +43,45 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithAlgorithms toRecipient(PGPPublicKey key) {
|
public WithAlgorithms toRecipient(PGPPublicKey key) {
|
||||||
|
if (!key.isEncryptionKey()) {
|
||||||
|
throw new IllegalStateException("Public Key " + Long.toHexString(key.getKeyID()) + " is not capable of encryption.");
|
||||||
|
}
|
||||||
EncryptionBuilder.this.encryptionKeys.add(key);
|
EncryptionBuilder.this.encryptionKeys.add(key);
|
||||||
return new WithAlgorithmsImpl();
|
return new WithAlgorithmsImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithAlgorithms toRecipients(Set<PGPPublicKey> keys) {
|
public WithAlgorithms toRecipients(Set<PGPPublicKeyRing> keys) {
|
||||||
EncryptionBuilder.this.encryptionKeys.addAll(keys);
|
for (PGPPublicKeyRing ring : keys) {
|
||||||
|
for (PGPPublicKey k : ring) {
|
||||||
|
if (k.isEncryptionKey()) {
|
||||||
|
EncryptionBuilder.this.encryptionKeys.add(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return new WithAlgorithmsImpl();
|
return new WithAlgorithmsImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithAlgorithms toRecipients(Set<Long> keyIds, Set<PGPPublicKeyRing> keyRings)
|
public WithAlgorithms toRecipients(Set<Long> keyIds, Set<PGPPublicKeyRingCollection> keys)
|
||||||
throws PublicKeyNotFoundException {
|
throws PublicKeyNotFoundException {
|
||||||
|
|
||||||
Set<PGPPublicKey> keys = new HashSet<>();
|
|
||||||
|
|
||||||
for (Long id : keyIds) {
|
|
||||||
PGPPublicKey key = null;
|
|
||||||
|
|
||||||
for (PGPPublicKeyRing ring : keyRings) {
|
|
||||||
key = ring.getPublicKey(id);
|
|
||||||
if (key != null) {
|
|
||||||
break; // Found key. Break inner loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == null) {
|
|
||||||
throw new PublicKeyNotFoundException(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
return toRecipients(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WithAlgorithms toRecipients(Set<Long> keyIds, PGPPublicKeyRingCollection keyRings)
|
|
||||||
throws PublicKeyNotFoundException {
|
|
||||||
|
|
||||||
Set<PGPPublicKeyRing> rings = new HashSet<>();
|
Set<PGPPublicKeyRing> rings = new HashSet<>();
|
||||||
|
|
||||||
for (Iterator<PGPPublicKeyRing> i = keyRings.getKeyRings(); i.hasNext();) {
|
for (PGPPublicKeyRingCollection collection : keys) {
|
||||||
rings.add(i.next());
|
for (long keyId : keyIds) {
|
||||||
|
try {
|
||||||
|
PGPPublicKeyRing ring = collection.getPublicKeyRing(keyId);
|
||||||
|
if (ring != null) {
|
||||||
|
rings.add(ring);
|
||||||
|
keyIds.remove(keyId);
|
||||||
|
}
|
||||||
|
} catch (PGPException e) {
|
||||||
|
throw new PublicKeyNotFoundException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return toRecipients(keyIds, rings);
|
return toRecipients(rings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,8 +93,21 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
|
||||||
class WithAlgorithmsImpl implements WithAlgorithms {
|
class WithAlgorithmsImpl implements WithAlgorithms {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WithAlgorithms andToSelf(Set<PGPPublicKey> keys) {
|
public WithAlgorithms andToSelf(PGPPublicKey key) {
|
||||||
EncryptionBuilder.this.encryptionKeys.addAll(keys);
|
EncryptionBuilder.this.encryptionKeys.add(key);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WithAlgorithms andToSelf(Set<PGPPublicKeyRing> keyRings) {
|
||||||
|
for (PGPPublicKeyRing ring : keyRings) {
|
||||||
|
for (Iterator<PGPPublicKey> i = ring.getPublicKeys(); i.hasNext(); ) {
|
||||||
|
PGPPublicKey key = i.next();
|
||||||
|
if (key.isEncryptionKey()) {
|
||||||
|
EncryptionBuilder.this.encryptionKeys.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,59 +122,56 @@ public class EncryptionBuilder implements EncryptionBuilderInterface {
|
||||||
|
|
||||||
return new SignWithImpl();
|
return new SignWithImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SignWith usingSecureAlgorithms() {
|
||||||
|
EncryptionBuilder.this.symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_256;
|
||||||
|
EncryptionBuilder.this.hashAlgorithm = HashAlgorithm.SHA512;
|
||||||
|
EncryptionBuilder.this.compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED;
|
||||||
|
|
||||||
|
return new SignWithImpl();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SignWithImpl implements SignWith {
|
class SignWithImpl implements SignWith {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Armor signWith(PGPSecretKey key, SecretKeyRingDecryptor decryptor) {
|
public Armor signWith(PGPSecretKeyRing key, SecretKeyRingProtector decryptor) {
|
||||||
EncryptionBuilder.this.signingKeys.add(key);
|
return signWith(Collections.singleton(key), decryptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Armor signWith(Set<PGPSecretKeyRing> keys, SecretKeyRingProtector decryptor) {
|
||||||
|
for (PGPSecretKeyRing key : keys) {
|
||||||
|
for (Iterator<PGPSecretKey> i = key.getSecretKeys(); i.hasNext(); ) {
|
||||||
|
PGPSecretKey s = i.next();
|
||||||
|
if (s.isSigningKey()) {
|
||||||
|
EncryptionBuilder.this.signingKeys.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
EncryptionBuilder.this.signingKeysDecryptor = decryptor;
|
EncryptionBuilder.this.signingKeysDecryptor = decryptor;
|
||||||
return new ArmorImpl();
|
return new ArmorImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Armor signWith(Set<PGPSecretKey> keys, SecretKeyRingDecryptor decryptor) {
|
public Armor signWith(Set<Long> keyIds, Set<PGPSecretKeyRingCollection> keyRings, SecretKeyRingProtector decryptor)
|
||||||
EncryptionBuilder.this.signingKeys.addAll(keys);
|
|
||||||
EncryptionBuilder.this.signingKeysDecryptor = decryptor;
|
|
||||||
return new ArmorImpl();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Armor signWith(Set<Long> keyIds, Set<PGPSecretKeyRing> keyRings, SecretKeyRingDecryptor decryptor)
|
|
||||||
throws SecretKeyNotFoundException {
|
throws SecretKeyNotFoundException {
|
||||||
Set<PGPSecretKey> keys = new HashSet<>();
|
|
||||||
|
|
||||||
for (Long id : keyIds) {
|
|
||||||
|
|
||||||
PGPSecretKey key = null;
|
|
||||||
|
|
||||||
for (PGPSecretKeyRing ring : keyRings) {
|
|
||||||
key = ring.getSecretKey(id);
|
|
||||||
if (key != null) {
|
|
||||||
break; // Found key. Break inner loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key == null) {
|
|
||||||
throw new SecretKeyNotFoundException(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
return signWith(keys, decryptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Armor signWith(Set<Long> keyIds, PGPSecretKeyRingCollection keys, SecretKeyRingDecryptor decryptor)
|
|
||||||
throws SecretKeyNotFoundException {
|
|
||||||
|
|
||||||
Set<PGPSecretKeyRing> rings = new HashSet<>();
|
Set<PGPSecretKeyRing> rings = new HashSet<>();
|
||||||
|
for (PGPSecretKeyRingCollection collection : keyRings) {
|
||||||
for (Iterator<PGPSecretKeyRing> i = keys.getKeyRings(); i.hasNext();) {
|
for (long keyId : keyIds) {
|
||||||
rings.add(i.next());
|
try {
|
||||||
|
PGPSecretKeyRing ring = collection.getSecretKeyRing(keyId);
|
||||||
|
if (ring != null) {
|
||||||
|
rings.add(ring);
|
||||||
|
keyIds.remove(keyId);
|
||||||
}
|
}
|
||||||
return signWith(keyIds, rings, decryptor);
|
} catch (PGPException e) {
|
||||||
|
throw new SecretKeyNotFoundException(keyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return signWith(rings, decryptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package de.vanitasvitae.crypto.pgpainless.encryption_signing;
|
package de.vanitasvitae.crypto.pgpainless.encryption_signing;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -10,11 +9,11 @@ import de.vanitasvitae.crypto.pgpainless.SecretKeyNotFoundException;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.CompressionAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.HashAlgorithm;
|
||||||
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
import de.vanitasvitae.crypto.pgpainless.algorithm.SymmetricKeyAlgorithm;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.SecretKeyRingProtector;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
|
||||||
|
@ -26,12 +25,9 @@ public interface EncryptionBuilderInterface {
|
||||||
|
|
||||||
WithAlgorithms toRecipient(PGPPublicKey key);
|
WithAlgorithms toRecipient(PGPPublicKey key);
|
||||||
|
|
||||||
WithAlgorithms toRecipients(Set<PGPPublicKey> keys);
|
WithAlgorithms toRecipients(Set<PGPPublicKeyRing> keys);
|
||||||
|
|
||||||
WithAlgorithms toRecipients(Set<Long> keyIds, Set<PGPPublicKeyRing> keyRings)
|
WithAlgorithms toRecipients(Set<Long> keyIds, Set<PGPPublicKeyRingCollection> keys)
|
||||||
throws PublicKeyNotFoundException;
|
|
||||||
|
|
||||||
WithAlgorithms toRecipients(Set<Long> keyIds, PGPPublicKeyRingCollection keys)
|
|
||||||
throws PublicKeyNotFoundException;
|
throws PublicKeyNotFoundException;
|
||||||
|
|
||||||
SignWith doNotEncrypt();
|
SignWith doNotEncrypt();
|
||||||
|
@ -40,24 +36,26 @@ public interface EncryptionBuilderInterface {
|
||||||
|
|
||||||
interface WithAlgorithms {
|
interface WithAlgorithms {
|
||||||
|
|
||||||
WithAlgorithms andToSelf(Set<PGPPublicKey> keys);
|
WithAlgorithms andToSelf(PGPPublicKey key);
|
||||||
|
|
||||||
|
WithAlgorithms andToSelf(Set<PGPPublicKeyRing> keys);
|
||||||
|
|
||||||
SignWith usingAlgorithms(SymmetricKeyAlgorithm symmetricKeyAlgorithm,
|
SignWith usingAlgorithms(SymmetricKeyAlgorithm symmetricKeyAlgorithm,
|
||||||
HashAlgorithm hashAlgorithm,
|
HashAlgorithm hashAlgorithm,
|
||||||
CompressionAlgorithm compressionAlgorithm);
|
CompressionAlgorithm compressionAlgorithm);
|
||||||
|
|
||||||
|
SignWith usingSecureAlgorithms();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SignWith {
|
interface SignWith {
|
||||||
|
|
||||||
Armor signWith(PGPSecretKey key, SecretKeyRingDecryptor decryptor);
|
Armor signWith(PGPSecretKeyRing key, SecretKeyRingProtector decryptor);
|
||||||
|
|
||||||
Armor signWith(Set<PGPSecretKey> keys, SecretKeyRingDecryptor decryptor);
|
Armor signWith(Set<PGPSecretKeyRing> keyRings, SecretKeyRingProtector decryptor)
|
||||||
|
|
||||||
Armor signWith(Set<Long> keyIds, Set<PGPSecretKeyRing> keyRings, SecretKeyRingDecryptor decryptor)
|
|
||||||
throws SecretKeyNotFoundException;
|
throws SecretKeyNotFoundException;
|
||||||
|
|
||||||
Armor signWith(Set<Long> keyIds, PGPSecretKeyRingCollection keys, SecretKeyRingDecryptor decryptor)
|
Armor signWith(Set<Long> keyIds, Set<PGPSecretKeyRingCollection> keys, SecretKeyRingProtector decryptor)
|
||||||
throws SecretKeyNotFoundException;
|
throws SecretKeyNotFoundException;
|
||||||
|
|
||||||
Armor doNotSign();
|
Armor doNotSign();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package de.vanitasvitae.crypto.pgpainless.encryption_signing;
|
package de.vanitasvitae.crypto.pgpainless.key;
|
||||||
|
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
|
|
||||||
public interface SecretKeyRingDecryptor {
|
public interface SecretKeyRingProtector {
|
||||||
|
|
||||||
PBESecretKeyDecryptor getDecryptor(Long keyId);
|
PBESecretKeyDecryptor getDecryptor(Long keyId);
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the {@link SecretKeyRingProtector} which assumes that all handled keys are not password protected.
|
||||||
|
*/
|
||||||
|
public class UnprotectedKeysProtector implements SecretKeyRingProtector {
|
||||||
|
@Override
|
||||||
|
public PBESecretKeyDecryptor getDecryptor(Long keyId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PBESecretKeyEncryptor getEncryptor(Long keyId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||||
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||||
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
|
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
|
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that describes a selection strategy for OpenPGP keys.
|
||||||
|
* @param <K> Type of the Key
|
||||||
|
* @param <R> Type of the KeyRing
|
||||||
|
* @param <O> Type that describes the owner of this key
|
||||||
|
*/
|
||||||
|
public interface KeySelectionStrategy<K, R, O> {
|
||||||
|
|
||||||
|
boolean accept(O identifier, K key);
|
||||||
|
|
||||||
|
Set<K> selectKeysFromKeyRing(O identifier, R ring);
|
||||||
|
|
||||||
|
MultiMap<O, K> selectKeysFromKeyRings(MultiMap<O, R> rings);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy which accepts {@link PGPPublicKey}s that are accepted by the abstract method
|
||||||
|
* {@link #accept(Object, Object)}.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of the key.
|
||||||
|
*/
|
||||||
|
public abstract class PublicKeySelectionStrategy<O> implements KeySelectionStrategy<PGPPublicKey, PGPPublicKeyRing, O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<PGPPublicKey> selectKeysFromKeyRing(O identifier, PGPPublicKeyRing ring) {
|
||||||
|
Set<PGPPublicKey> keys = new HashSet<>();
|
||||||
|
for (Iterator<PGPPublicKey> i = ring.getPublicKeys(); i.hasNext(); ) {
|
||||||
|
PGPPublicKey key = i.next();
|
||||||
|
if (accept(identifier, key)) keys.add(key);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiMap<O, PGPPublicKey> selectKeysFromKeyRings(MultiMap<O, PGPPublicKeyRing> keyRings) {
|
||||||
|
MultiMap<O, PGPPublicKey> keys = new MultiMap<>();
|
||||||
|
for (O identifier : keyRings.keySet()) {
|
||||||
|
for (PGPPublicKeyRing ring : keyRings.get(identifier)) {
|
||||||
|
keys.put(identifier, selectKeysFromKeyRing(identifier, ring));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy which accepts {@link PGPSecretKey}s that are accepted by the abstract method
|
||||||
|
* {@link #accept(Object, Object)}.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of the key.
|
||||||
|
*/
|
||||||
|
public abstract class SecretKeySelectionStrategy<O> implements KeySelectionStrategy<PGPSecretKey, PGPSecretKeyRing, O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<PGPSecretKey> selectKeysFromKeyRing(O identifier, PGPSecretKeyRing ring) {
|
||||||
|
Set<PGPSecretKey> keys = new HashSet<>();
|
||||||
|
for (Iterator<PGPSecretKey> i = ring.getSecretKeys(); i.hasNext(); ) {
|
||||||
|
PGPSecretKey key = i.next();
|
||||||
|
if (accept(identifier, key)) keys.add(key);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiMap<O, PGPSecretKey> selectKeysFromKeyRings(MultiMap<O, PGPSecretKeyRing> keyRings) {
|
||||||
|
MultiMap<O, PGPSecretKey> keys = new MultiMap<>();
|
||||||
|
for (O identifier : keyRings.keySet()) {
|
||||||
|
for (PGPSecretKeyRing ring : keyRings.get(identifier)) {
|
||||||
|
keys.put(identifier, selectKeysFromKeyRing(identifier, ring));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key.impl;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy that only accepts {@link PGPPublicKey}s which are capable of encryption.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of the key (not used for decision).
|
||||||
|
*/
|
||||||
|
public class EncryptionKeySelectionStrategy<O> extends PublicKeySelectionStrategy<O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPPublicKey key) {
|
||||||
|
return key.isEncryptionKey();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key.impl;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.SecretKeySelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategies that do accept only keys, which have no revocation.
|
||||||
|
*/
|
||||||
|
public class NoRevocation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy which only accepts {@link PGPPublicKey}s which have no revocation.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of this key (not used for this decision).
|
||||||
|
*/
|
||||||
|
public static class PubKeySelectionStrategy<O> extends PublicKeySelectionStrategy<O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPPublicKey key) {
|
||||||
|
return !key.hasRevocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy which only accepts {@link PGPSecretKey}s which have no revocation.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of this key (not used for this decision).
|
||||||
|
*/
|
||||||
|
public static class SecKeySelectionStrategy<O> extends SecretKeySelectionStrategy<O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPSecretKey key) {
|
||||||
|
return !key.getPublicKey().hasRevocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.key.impl;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.SecretKeySelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key Selection Strategy that only accepts {@link PGPSecretKey}s which are capable of signing.
|
||||||
|
*
|
||||||
|
* @param <O> Type that describes the owner of the key (not used for this decision).
|
||||||
|
*/
|
||||||
|
public class SignatureKeySelectionStrategy<O> extends SecretKeySelectionStrategy<O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPSecretKey key) {
|
||||||
|
return key.isSigningKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
|
||||||
|
public interface KeyRingSelectionStrategy<R, C, O> {
|
||||||
|
|
||||||
|
boolean accept(O identifier, R keyRing);
|
||||||
|
|
||||||
|
Set<R> selectKeyRingsFromCollection(O identifier, C keyRingCollection);
|
||||||
|
|
||||||
|
MultiMap<O, R> selectKeyRingsFromCollections(MultiMap<O, C> keyRingCollections);
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
|
||||||
|
public abstract class PublicKeyRingSelectionStrategy<O> implements KeyRingSelectionStrategy<PGPPublicKeyRing, PGPPublicKeyRingCollection, O> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<PGPPublicKeyRing> selectKeyRingsFromCollection(O identifier, PGPPublicKeyRingCollection keyRingCollection) {
|
||||||
|
Set<PGPPublicKeyRing> accepted = new HashSet<>();
|
||||||
|
for (Iterator<PGPPublicKeyRing> i = keyRingCollection.getKeyRings(); i.hasNext(); ) {
|
||||||
|
PGPPublicKeyRing ring = i.next();
|
||||||
|
if (accept(identifier, ring)) accepted.add(ring);
|
||||||
|
}
|
||||||
|
return accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiMap<O, PGPPublicKeyRing> selectKeyRingsFromCollections(MultiMap<O, PGPPublicKeyRingCollection> keyRingCollections) {
|
||||||
|
MultiMap<O, PGPPublicKeyRing> keyRings = new MultiMap<>();
|
||||||
|
for (O identifier : keyRingCollections.keySet()) {
|
||||||
|
for (PGPPublicKeyRingCollection collection : keyRingCollections.get(identifier)) {
|
||||||
|
keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyRings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
|
||||||
|
public abstract class SecretKeyRingSelectionStrategy<O> implements KeyRingSelectionStrategy<PGPSecretKeyRing, PGPSecretKeyRingCollection, O> {
|
||||||
|
@Override
|
||||||
|
public Set<PGPSecretKeyRing> selectKeyRingsFromCollection(O identifier, PGPSecretKeyRingCollection keyRingCollection) {
|
||||||
|
Set<PGPSecretKeyRing> accepted = new HashSet<>();
|
||||||
|
for (Iterator<PGPSecretKeyRing> i = keyRingCollection.getKeyRings(); i.hasNext(); ) {
|
||||||
|
PGPSecretKeyRing ring = i.next();
|
||||||
|
if (accept(identifier, ring)) accepted.add(ring);
|
||||||
|
}
|
||||||
|
return accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiMap<O, PGPSecretKeyRing> selectKeyRingsFromCollections(MultiMap<O, PGPSecretKeyRingCollection> keyRingCollections) {
|
||||||
|
MultiMap<O, PGPSecretKeyRing> keyRings = new MultiMap<>();
|
||||||
|
for (O identifier : keyRingCollections.keySet()) {
|
||||||
|
for (PGPSecretKeyRingCollection collection : keyRingCollections.get(identifier)) {
|
||||||
|
keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyRings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring.impl;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
|
||||||
|
public class Email {
|
||||||
|
|
||||||
|
public static class PubRingSelectionStrategy extends PartialUserId.PubRingSelectionStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String email, PGPPublicKey key) {
|
||||||
|
// Ensure, that email address is encapsulated in "<",">"
|
||||||
|
if (!email.matches("^<.+>$")) {
|
||||||
|
email = "<" + email + ">";
|
||||||
|
}
|
||||||
|
return super.accept(email, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SecRingSelectionStrategy extends PartialUserId.SecRingSelectionStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String email, PGPSecretKey key) {
|
||||||
|
// Ensure, that email address is encapsulated in "<",">"
|
||||||
|
if (!email.matches("^<.+>$")) {
|
||||||
|
email = "<" + email + ">";
|
||||||
|
}
|
||||||
|
return super.accept(email, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring.impl;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
public class ExactUserId {
|
||||||
|
|
||||||
|
public static class PubRingSelectionStrategy extends PublicKeyRingSelectionStrategy<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String identifier, PGPPublicKeyRing keyRing) {
|
||||||
|
Iterator<String> userIds = keyRing.getPublicKey().getUserIDs();
|
||||||
|
while (userIds.hasNext()) {
|
||||||
|
if (userIds.next().equals(identifier)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SecRingSelectionStrategy extends SecretKeyRingSelectionStrategy<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String identifier, PGPSecretKeyRing keyRing) {
|
||||||
|
Iterator<String> userIds = keyRing.getPublicKey().getUserIDs();
|
||||||
|
while (userIds.hasNext()) {
|
||||||
|
if (userIds.next().equals(identifier)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring.impl;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.PublicKeySelectionStrategy;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.key.SecretKeySelectionStrategy;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
|
||||||
|
public class PartialUserId {
|
||||||
|
|
||||||
|
public static class PubRingSelectionStrategy extends PublicKeySelectionStrategy<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String identifier, PGPPublicKey key) {
|
||||||
|
for (Iterator<String> userIds = key.getUserIDs(); userIds.hasNext(); ) {
|
||||||
|
String userId = userIds.next();
|
||||||
|
if (userId.contains(identifier)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SecRingSelectionStrategy extends SecretKeySelectionStrategy<String> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String identifier, PGPSecretKey key) {
|
||||||
|
for (Iterator userIds = key.getUserIDs(); userIds.hasNext(); ) {
|
||||||
|
String userId = (String) userIds.next();
|
||||||
|
if (userId.contains(identifier)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring.impl;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy;
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.util.MultiMap;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
public class Whitelist {
|
||||||
|
|
||||||
|
public static class PubRingSelectionStrategy<O> extends PublicKeyRingSelectionStrategy<O> {
|
||||||
|
|
||||||
|
private final MultiMap<O, Long> whitelist;
|
||||||
|
|
||||||
|
public PubRingSelectionStrategy(MultiMap<O, Long> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PubRingSelectionStrategy(Map<O, Set<Long>> whitelist) {
|
||||||
|
this.whitelist = new MultiMap<>(whitelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPPublicKeyRing keyRing) {
|
||||||
|
Set<Long> whitelistedKeyIds = whitelist.get(identifier);
|
||||||
|
|
||||||
|
if (whitelistedKeyIds == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SecRingSelectionStrategy<O> extends SecretKeyRingSelectionStrategy<O> {
|
||||||
|
|
||||||
|
private final MultiMap<O, Long> whitelist;
|
||||||
|
|
||||||
|
public SecRingSelectionStrategy(MultiMap<O, Long> whitelist) {
|
||||||
|
this.whitelist = whitelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecRingSelectionStrategy(Map<O, Set<Long>> whitelist) {
|
||||||
|
this.whitelist = new MultiMap<>(whitelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(O identifier, PGPSecretKeyRing keyRing) {
|
||||||
|
Set<Long> whitelistedKeyIds = whitelist.get(identifier);
|
||||||
|
|
||||||
|
if (whitelistedKeyIds == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.key.selection.keyring.impl;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
public class XMPP {
|
||||||
|
|
||||||
|
public static class PubRingSelectionStrategy extends ExactUserId.PubRingSelectionStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String jid, PGPPublicKeyRing keyRing) {
|
||||||
|
return super.accept("xmpp:" + jid, keyRing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SecRingSelectionStrategy extends ExactUserId.SecRingSelectionStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(String jid, PGPSecretKeyRing keyRing) {
|
||||||
|
return super.accept("xmpp:" + jid, keyRing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless.util;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class MultiMap<K, V> {
|
||||||
|
|
||||||
|
private final Map<K, Set<V>> map;
|
||||||
|
|
||||||
|
public MultiMap() {
|
||||||
|
map = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiMap(MultiMap<K, V> other) {
|
||||||
|
this.map = new HashMap<>();
|
||||||
|
for (K k : other.map.keySet()) {
|
||||||
|
map.put(k, new HashSet<>(other.map.get(k)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MultiMap(Map<K, Set<V>> content) {
|
||||||
|
this.map = new HashMap<>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return map.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsKey(Object o) {
|
||||||
|
return map.containsKey(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsValue(Object o) {
|
||||||
|
for (Set<V> values : map.values()) {
|
||||||
|
if (values.contains(o)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<V> get(Object o) {
|
||||||
|
return map.get(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(K k, V v) {
|
||||||
|
Set<V> values = map.get(k);
|
||||||
|
if (values == null) {
|
||||||
|
values = new HashSet<>();
|
||||||
|
map.put(k, values);
|
||||||
|
}
|
||||||
|
values.add(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(K k, Set<V> vs) {
|
||||||
|
for (V v : vs) {
|
||||||
|
put(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Object o) {
|
||||||
|
for (Set<V> values : map.values()) {
|
||||||
|
values.remove(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAll(Map<? extends K, ? extends Set<V>> _map) {
|
||||||
|
for (K key : _map.keySet()) {
|
||||||
|
Set<V> vs = this.map.get(key);
|
||||||
|
if (vs == null) {
|
||||||
|
vs = new HashSet<>();
|
||||||
|
this.map.put(key, vs);
|
||||||
|
}
|
||||||
|
vs.addAll(_map.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<K> keySet() {
|
||||||
|
return map.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Set<V>> values() {
|
||||||
|
return map.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Map.Entry<K, Set<V>>> entrySet() {
|
||||||
|
return map.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(o instanceof MultiMap)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.equals(((MultiMap) o).map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return map.hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static junit.framework.TestCase.assertTrue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import de.vanitasvitae.crypto.pgpainless.key.UnprotectedKeysProtector;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPUtil;
|
||||||
|
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
|
||||||
|
import org.bouncycastle.util.io.Streams;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class EncryptDecryptTest {
|
||||||
|
PGPSecretKeyRing juliet = new PGPSecretKeyRing(PGPUtil.getDecoderStream(new ByteArrayInputStream(TestKeys.JULIET_PRIV.getBytes())), new BcKeyFingerprintCalculator());
|
||||||
|
PGPSecretKeyRing romeo = new PGPSecretKeyRing(PGPUtil.getDecoderStream(new ByteArrayInputStream(TestKeys.ROMEO_PRIV.getBytes())), new BcKeyFingerprintCalculator());
|
||||||
|
|
||||||
|
public EncryptDecryptTest() throws IOException, PGPException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void keyIdTest() {
|
||||||
|
assertEquals("b4b509cb5936e03e", Long.toHexString(juliet.getSecretKey().getKeyID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws IOException, PGPException {
|
||||||
|
PGPPublicKeyRing jPub = new PGPPublicKeyRing(PGPUtil.getDecoderStream(new ByteArrayInputStream(TestKeys.JULIET_PUB.getBytes())), new BcKeyFingerprintCalculator());
|
||||||
|
|
||||||
|
ByteArrayOutputStream toEncrypted = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
OutputStream encryptor = PGPainless.createEncryptor().onOutputStream(toEncrypted)
|
||||||
|
.toRecipient(jPub.getPublicKey())
|
||||||
|
.usingSecureAlgorithms()
|
||||||
|
.signWith(new PGPSecretKeyRing(PGPUtil.getDecoderStream(new ByteArrayInputStream(TestKeys.JULIET_PRIV.getBytes())), new BcKeyFingerprintCalculator()), new UnprotectedKeysProtector())
|
||||||
|
.asciiArmor();
|
||||||
|
|
||||||
|
String message = "This message is encrypted using OpenPGP";
|
||||||
|
ByteArrayInputStream fromPlain = new ByteArrayInputStream(message.getBytes());
|
||||||
|
|
||||||
|
Streams.pipeAll(fromPlain, encryptor);
|
||||||
|
fromPlain.close();
|
||||||
|
encryptor.close();
|
||||||
|
|
||||||
|
System.out.println(new String(toEncrypted.toByteArray()));
|
||||||
|
|
||||||
|
|
||||||
|
ByteArrayInputStream fromEncrypted = new ByteArrayInputStream(toEncrypted.toByteArray());
|
||||||
|
ByteArrayOutputStream toPlain = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
PainlessResult.ResultAndInputStream resultAndInputStream = PGPainless.createDecryptor()
|
||||||
|
.onInputStream(fromEncrypted)
|
||||||
|
.decryptWith(new PGPSecretKeyRingCollection(Collections.singleton(juliet)),
|
||||||
|
new UnprotectedKeysProtector())
|
||||||
|
.doNotVerify()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InputStream decryptor = resultAndInputStream.getInputStream();
|
||||||
|
|
||||||
|
Streams.pipeAll(decryptor, toPlain);
|
||||||
|
|
||||||
|
fromEncrypted.close();
|
||||||
|
decryptor.close();
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals(message.getBytes(), toPlain.toByteArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException, PGPException {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
EncryptDecryptTest test = new EncryptDecryptTest();
|
||||||
|
test.decryptVerifyTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void decryptVerifyTest() throws IOException, PGPException {
|
||||||
|
String encryptedMessage = "-----BEGIN PGP MESSAGE-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"hQGMAwAAAAAAAAAAAQwAoJtfpcBPCwhUzzHuVIcBzBLyfIWT/EJ527neb46lN56S\n" +
|
||||||
|
"B05BTIRudIeCsPYz81jwiFi/k0MBecRfozZ1xCPByo8ohSvRgzEHEkCNgObQ1bz0\n" +
|
||||||
|
"iB+Xb76OEzFOCPUebTaVscLNf8ak/GSzaW7jDc+5vnvDf7cV0x26pe4odpS/U5Tr\n" +
|
||||||
|
"cO3wb/47K+sJ1cxJmPtcD41O02xu3QisQKPrimM0Kue6ziGeKyw1RkSowv9U47TK\n" +
|
||||||
|
"wppPCHOTli2Nf+gZizF1oyQZzPGst4fjujygcIoajplfW9nZvxsbmYRSLSdmV9m6\n" +
|
||||||
|
"k1jQbPDUhVs0gstH92C6hPpoBWxoxkHcwz8gy36nCyB6cYGyq3oN1UnGU4afPyD5\n" +
|
||||||
|
"SmmEjELBd2i2Ll/DYk2x06SnKZMQuWrSCZzWgl/9HsPo5ydVb97OjuEpWtW9xDMA\n" +
|
||||||
|
"KlYPNWEq+b+akOEstNraC3pfVKvypz6ZzaMAS1gWWNYg8dlwBJOUVMSo7iLaUQkK\n" +
|
||||||
|
"yp4uH1DlsyVu1atCUc8thQIMAwAAAAAAAAAAAQ/5AdiZ/sG859Y/rGR7U/8MzGg0\n" +
|
||||||
|
"j3f2vrgDF/0NRRk5aqd1lb4CaZvrztcYqW3cEK7iF9rKwImZZiWIptjJ9Mz6f1Zl\n" +
|
||||||
|
"FbODObSVRZAcZqYGswEEfsQvpQFlwG6Qx48OaQaDPr147raFI3C3kEU9Nb2VBg8+\n" +
|
||||||
|
"MevJaXJft5PXwUTG2Qvfxqr/3hfGAwB4/zHwA8vFd1np3spryfrC9Dq8UXUoRXIS\n" +
|
||||||
|
"xaFPiLEYt8rLef8f11OypEpmknIibu9jjJtuVZo+SjP6jgLHDwM7rqCZFITM2Qra\n" +
|
||||||
|
"2iBCt8YVcIiTK137t+EfsdVN/KHiRbc++e9zUbGMEextbtNbdoFOU4dnKBm6Su8l\n" +
|
||||||
|
"Z5UerNbR8D7+xJKfAEabdi0qI7QFmhTZ/4H/22yrvoD9jMFSBXUTE9ENIX9Hfqom\n" +
|
||||||
|
"UdsHfuE+5PC0JjkZkhchDO1M7XBX++lBCFsq2abfdpmaX+roVX0iTGboxr5Ag1Cf\n" +
|
||||||
|
"T2zWyRX/XKnvmdeGICV5qjy/ThuSWvAclazyFxWLamMztJq5BRpfAzKNQRDqlmKw\n" +
|
||||||
|
"eePtKW2EWUIjFQ5/UAM6Edu/K34ksFxb0w6YGLzQSskGr7gGAipLmpek6vcUSUA1\n" +
|
||||||
|
"oc9XJGdpx93GDRcqDjKDt/ej06VxG33/pW65ntf5QM/+LScGqaLhAHyEOsBzVIXY\n" +
|
||||||
|
"BONcadSgzkTrlbSMGAmFAQwDtLUJy1k24D4BB/0brqR0UN1LtO+Lc/vN6X/Um2CZ\n" +
|
||||||
|
"CM6MRhPnXP63Q9HHkGJ2S8zGWvQLwWL9Y14CFCgm6rACLBSIyPbihhC2OC8afhSy\n" +
|
||||||
|
"apGkdHtdghS2egs2U8qlJ2Y32IAG9CcUtNkRjxp+/RWSrmZeuL4l7DXCyH5lUadx\n" +
|
||||||
|
"5bPZhAHqW9408q2rQd9dBg2o7ciGXTJSKVahjuiB/O0gchOnbqnlYJbKbCkntXUo\n" +
|
||||||
|
"c7h4w1e8MutisSJorh7kbxgxUJSboZzEkiUfnoacPTz6bL+re9tmnpvlee70sIyM\n" +
|
||||||
|
"BiYRCyPw7Ice4R3XyWtsMTjT/wjZ//whMpWdy2drcJSyhh+GQMbekTVsNWod0lQB\n" +
|
||||||
|
"JTPUfti2VU7PMB3LjJA+l/T9iWPPx8lirnLhXOOerWKH9I5Wo4Kqv/47aJhfMO6+\n" +
|
||||||
|
"jmLekAOylq+9DizrslW/EUgQyjIbcWfmyMiV6E2RwbI93tE=\n" +
|
||||||
|
"=GAhR\n" +
|
||||||
|
"-----END PGP MESSAGE-----";
|
||||||
|
|
||||||
|
PainlessResult.ResultAndInputStream resultAndInputStream = PGPainless.createDecryptor()
|
||||||
|
.onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes()))
|
||||||
|
.decryptWith(new PGPSecretKeyRingCollection(Collections.singleton(juliet)), new UnprotectedKeysProtector())
|
||||||
|
.verifyWith(
|
||||||
|
Collections.singleton(juliet.getPublicKey().getKeyID()),
|
||||||
|
Collections.singleton(
|
||||||
|
new PGPPublicKeyRing(
|
||||||
|
PGPUtil.getDecoderStream(new ByteArrayInputStream(TestKeys.JULIET_PUB.getBytes())),
|
||||||
|
new BcKeyFingerprintCalculator())))
|
||||||
|
.ignoreMissingPublicKeys()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
InputStream decryptor = resultAndInputStream.getInputStream();
|
||||||
|
ByteArrayOutputStream toPlain = new ByteArrayOutputStream();
|
||||||
|
Streams.pipeAll(decryptor, toPlain);
|
||||||
|
decryptor.close();
|
||||||
|
toPlain.close();
|
||||||
|
|
||||||
|
assertTrue(Arrays.equals("This message is encrypted".getBytes(), toPlain.toByteArray()));
|
||||||
|
}
|
||||||
|
}
|
142
src/test/java/de/vanitasvitae/crypto/pgpainless/TestKeys.java
Normal file
142
src/test/java/de/vanitasvitae/crypto/pgpainless/TestKeys.java
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 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 de.vanitasvitae.crypto.pgpainless;
|
||||||
|
|
||||||
|
public class TestKeys {
|
||||||
|
|
||||||
|
public static final String JULIET_UID = "xmpp:juliet@capulet.lit";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key of xmpp:juliet@capulet.lit.
|
||||||
|
*/
|
||||||
|
public static final String JULIET_PUB = "" +
|
||||||
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"mQENBFrxov4BCAChZwPrBxxIlwzpieR5T2pnaOZLWH0WqSON6rVjvfbJHWdDi3Th\n" +
|
||||||
|
"remHW4gg4IBSTXkVFDIeQNVcOvGNgMg3Oe/x0I6FK12jrw9prycmjFxQ7A0ix7ZG\n" +
|
||||||
|
"UkTF5jITgzJbkH100gYfXtZsfTyvgISSAT//6vvvQPZ3zCr09XvAG0CyQ1BhULsv\n" +
|
||||||
|
"mVRe4Oh5b0VK4kLdv+GiA/T+49UKZj6lne9Vdti16ZIj7teVCbicfdhpTzsjur42\n" +
|
||||||
|
"r8ptouKAuyFPw9KnGNwVlIiv5jt/Kit/LoOBenh74sitsCXq8IQ9kKp/eNt8TF4u\n" +
|
||||||
|
"D4IGpxnJfB8XCiixYHoFEajmQBVJXNYtvoPvABEBAAG0F3htcHA6anVsaWV0QGNh\n" +
|
||||||
|
"cHVsZXQubGl0iQFOBBMBCAA4FiEEHQGMdy34xe+GodzJtLUJy1k24D4FAlrxov4C\n" +
|
||||||
|
"Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQtLUJy1k24D6H7AgAoTjx4ezc\n" +
|
||||||
|
"A83NeOY3tMHVQTM7hKuy0wMcSzQgVgJmhLYRZS8r+FocPZua/eke49GPhe2yozvl\n" +
|
||||||
|
"ByWHtotklQeJiwOKxuPKMzneVA1ZK3/9LdGvtZlHMcAkEKDhit8HIaEcsFd4Z1re\n" +
|
||||||
|
"EhF2lyvY/E+rrx9YxV0QjisSWV2dSptv6FeGSztr9e5E+Head6hEQhsugiTVRF+1\n" +
|
||||||
|
"6mG90te0WGQ9YNiJ2FJovx5kBLTTuhwUz8Oacqihd2+RDDI5p3wJoogVL31aNb4n\n" +
|
||||||
|
"c7dGo8ieJPHGlkBsOfmreSxijTodZz9MXsgcx7b//u0uQryViJoZHWbtnXOFjjNc\n" +
|
||||||
|
"GWBtS084NKWl9w==\n" +
|
||||||
|
"=ecwX\n" +
|
||||||
|
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key of xmpp:juliet@capulet.lit.
|
||||||
|
*/
|
||||||
|
public static final String JULIET_PRIV = "" +
|
||||||
|
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"lQOYBFrxov4BCAChZwPrBxxIlwzpieR5T2pnaOZLWH0WqSON6rVjvfbJHWdDi3Th\n" +
|
||||||
|
"remHW4gg4IBSTXkVFDIeQNVcOvGNgMg3Oe/x0I6FK12jrw9prycmjFxQ7A0ix7ZG\n" +
|
||||||
|
"UkTF5jITgzJbkH100gYfXtZsfTyvgISSAT//6vvvQPZ3zCr09XvAG0CyQ1BhULsv\n" +
|
||||||
|
"mVRe4Oh5b0VK4kLdv+GiA/T+49UKZj6lne9Vdti16ZIj7teVCbicfdhpTzsjur42\n" +
|
||||||
|
"r8ptouKAuyFPw9KnGNwVlIiv5jt/Kit/LoOBenh74sitsCXq8IQ9kKp/eNt8TF4u\n" +
|
||||||
|
"D4IGpxnJfB8XCiixYHoFEajmQBVJXNYtvoPvABEBAAEAB/4jMbXagW3q7DkOEZnm\n" +
|
||||||
|
"0+jVTLvu0QhRsScGEphj+++8sfMq+NVPQp9p+w0Hcjy49ZjB/mnhS+zaVCYI33yJ\n" +
|
||||||
|
"AlKubXYuVqLwBsO7HUzRrIiSwq4ol9jIo7bIWmYv+As6iRq6JvPb0k+6T2K0uDbw\n" +
|
||||||
|
"KWKduM0fwhAcVkJFsOO/o5GrbQaJc3oioFk8uFWTnO+FPBRTJ9oTlVG2M/tEatZK\n" +
|
||||||
|
"gl7I8Ukl0YYruCNUFKZ0tvO8HqulxBgUbGPBer1uOlfUD4RXdc8/PUiFKNo48XSu\n" +
|
||||||
|
"ZUEAZKGbFBjuX5Z8ha7+sUMEYEt70qlbkiLQxgHKAmpyridAk3q/SB3y2VB8Ik7I\n" +
|
||||||
|
"gpExBADInzLROYuUcXqmty+znVwm6nRIB75JBAy778zgIxx1v0O3QlVnR+YI8gJM\n" +
|
||||||
|
"mQ/9pD6LyP9hktWDmJxG8tX+kSuIp3wNJc5EMeXtCCmkUW0CP1gUhAbNW3MezKa5\n" +
|
||||||
|
"II5IhE9RgIsYqSU8ZgeIh72ON8XTp8i/wGipCXvJPggSAMXukQQAzfRmtLW+JHEK\n" +
|
||||||
|
"B8ETIYh8IUjXJ6TVlmuBwZ0eXjCpqy9arJi6tacesDJwnL3sqOMQWUmqGsCGSKA5\n" +
|
||||||
|
"cLITkVsxX/htIq8GFyludjg8t4Nr+fOGfChEq8QE0PHE2CgskQMHpfHvfIdnwKve\n" +
|
||||||
|
"Fg2Q8twoMw849O6PF3k/848Z65lDin8EAMDbuPWL7KU2sWeqvDEuoulS5K1gsq8X\n" +
|
||||||
|
"p3Od3+f0OG8YViMjKcVlSKHVvdlK4dlsccJrJJx6VzotV47LsmvVbzDwUE//MYq7\n" +
|
||||||
|
"QwwQetZbpdQZDysSGVqHMTuAg/1pr2u5rqh4cFqCYatgZwinEI2TQMXEqnSc+mj8\n" +
|
||||||
|
"xp/LNq5BZZQuO4y0F3htcHA6anVsaWV0QGNhcHVsZXQubGl0iQFOBBMBCAA4FiEE\n" +
|
||||||
|
"HQGMdy34xe+GodzJtLUJy1k24D4FAlrxov4CGy8FCwkIBwIGFQoJCAsCBBYCAwEC\n" +
|
||||||
|
"HgECF4AACgkQtLUJy1k24D6H7AgAoTjx4ezcA83NeOY3tMHVQTM7hKuy0wMcSzQg\n" +
|
||||||
|
"VgJmhLYRZS8r+FocPZua/eke49GPhe2yozvlByWHtotklQeJiwOKxuPKMzneVA1Z\n" +
|
||||||
|
"K3/9LdGvtZlHMcAkEKDhit8HIaEcsFd4Z1reEhF2lyvY/E+rrx9YxV0QjisSWV2d\n" +
|
||||||
|
"Sptv6FeGSztr9e5E+Head6hEQhsugiTVRF+16mG90te0WGQ9YNiJ2FJovx5kBLTT\n" +
|
||||||
|
"uhwUz8Oacqihd2+RDDI5p3wJoogVL31aNb4nc7dGo8ieJPHGlkBsOfmreSxijTod\n" +
|
||||||
|
"Zz9MXsgcx7b//u0uQryViJoZHWbtnXOFjjNcGWBtS084NKWl9w==\n" +
|
||||||
|
"=yPPE\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
public static final String ROMEO_UID = "xmpp:romeo@montague.lit";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key of xmpp:romeo@montague.lit.
|
||||||
|
*/
|
||||||
|
public static final String ROMEO_PUB = "" +
|
||||||
|
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"mQENBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" +
|
||||||
|
"Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" +
|
||||||
|
"CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" +
|
||||||
|
"iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" +
|
||||||
|
"Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" +
|
||||||
|
"XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAG0F3htcHA6cm9tZW9AbW9u\n" +
|
||||||
|
"dGFndWUubGl0iQFOBBMBCAA4FiEENdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkC\n" +
|
||||||
|
"Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr\n" +
|
||||||
|
"2aQmDN3OqRM4M4yRL3oyYMkCKIjqD6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCC\n" +
|
||||||
|
"K3bKKq3m71AQ7evDhKGshacPYesiDvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuG\n" +
|
||||||
|
"ANy1jYgtCEuYw7D+EsqNDdn8Xh+k/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfV\n" +
|
||||||
|
"AGFbuqryg48dXtnuzAPKcdgMTTMSnmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9\n" +
|
||||||
|
"g65i5EXenkbc2h0TRDQ4lDFQyModqFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3\n" +
|
||||||
|
"Bx5vYRDVmE3jeg==\n" +
|
||||||
|
"=2jSg\n" +
|
||||||
|
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private key of xmpp:romeo@montague.lit.
|
||||||
|
*/
|
||||||
|
public static final String ROMEO_PRIV = "" +
|
||||||
|
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"lQOYBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" +
|
||||||
|
"Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" +
|
||||||
|
"CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" +
|
||||||
|
"iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" +
|
||||||
|
"Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" +
|
||||||
|
"XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAEAB/4mu5p69/hRQ+UikWie\n" +
|
||||||
|
"Yun9rZ4hSBR+pR5kaifA4/rV1Km2PZ4HujiaYyRO6beDOgWkF7IlpezCfzBQc2ce\n" +
|
||||||
|
"ailkVemqHzIgV8CzQmhE8sHlzlr/wjXsXaJpRSCJxDG7PnRoJmt2b/W512WFSKQk\n" +
|
||||||
|
"vDklAVh4U1vlsqhCGWr4DmuJbJkRyDhcX01tplRwim283F7bGqRcMBmKMZHiMgVc\n" +
|
||||||
|
"0u84EYKKVizJ3YAaaVqZyHb4qdeKK2ak3fPNuGT/oGd2sxnkL+BZGjJpu3RGpTA1\n" +
|
||||||
|
"tbOvOQnJGHQtABFxE8n6H9dHPJGtgyz2+udjUhL/P/E3PDoXazZkXRq2oHZKgg0f\n" +
|
||||||
|
"AwOBBADsWncHgvz15rXPF7O6AivbGTJ5ctkgVy4U3Fu2sk9rf0fx0sryBSqtTBw1\n" +
|
||||||
|
"Uvn/p9RwTsKw6fng6Nf78xpZFlUDB00YCcuWkGodxvjTAyB0dtBmkhopeKi0dmHh\n" +
|
||||||
|
"ndnR6Pv0CsXu8nG7lUi+q6s3oc4h2OfDBhrqsyYY5M2gGit3dQQA9TNuinJD9XXv\n" +
|
||||||
|
"QRyauMnSJ5xRcfOu8QCxZlllCvffZjSGCPoVjUpJEe9qsVbXVj2GYCxjLCSXV0V+\n" +
|
||||||
|
"vlJfdPrl1BhZ3fmEpg0u7SyGDDOe8fe1ehk5sAeL8O0eFWlPSEaEccsjlpJ2FO0n\n" +
|
||||||
|
"P04SZdOeM6wmhDTEDzpFnjbPndQTH+ED/R1zNzr55DvxQodmrW/BvTmhGQ22rHtk\n" +
|
||||||
|
"IUfbeMaVfUvNLJA/JksrUIx3Gga9QCDZgfm1RsRhLUlHiqTQe23sPWgKOsbf5O1j\n" +
|
||||||
|
"XJZaCNZ7LloVQbkG7xFcnb/n1+JjBr4FxXjAA6cY/iRGlznjIIaasyklKm1/4LuQ\n" +
|
||||||
|
"hnH3QqTvCN3dOFS0F3htcHA6cm9tZW9AbW9udGFndWUubGl0iQFOBBMBCAA4FiEE\n" +
|
||||||
|
"NdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkCGy8FCwkIBwIGFQoJCAsCBBYCAwEC\n" +
|
||||||
|
"HgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr2aQmDN3OqRM4M4yRL3oyYMkCKIjq\n" +
|
||||||
|
"D6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCCK3bKKq3m71AQ7evDhKGshacPYesi\n" +
|
||||||
|
"DvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuGANy1jYgtCEuYw7D+EsqNDdn8Xh+k\n" +
|
||||||
|
"/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfVAGFbuqryg48dXtnuzAPKcdgMTTMS\n" +
|
||||||
|
"nmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9g65i5EXenkbc2h0TRDQ4lDFQyMod\n" +
|
||||||
|
"qFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3Bx5vYRDVmE3jeg==\n" +
|
||||||
|
"=LZ1b\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
}
|
Loading…
Reference in a new issue