mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-03-03 02:42:00 -05:00
wrapped-key-ring: first steps, get rid of key imports in decryptverify and signencrypt
This commit is contained in:
parent
4053e1ebd7
commit
4b3cfd4fa4
@ -0,0 +1,61 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
|
||||||
|
public abstract class CachedKeyRing {
|
||||||
|
|
||||||
|
private final long mMasterKeyId;
|
||||||
|
private final int mKeySize;
|
||||||
|
private final boolean mIsRevoked;
|
||||||
|
private final boolean mCanCertify;
|
||||||
|
private final long mCreation;
|
||||||
|
private final long mExpiry;
|
||||||
|
private final int mAlgorithm;
|
||||||
|
private final byte[] mFingerprint;
|
||||||
|
private final String mUserId;
|
||||||
|
private final int mVerified;
|
||||||
|
private final boolean mHasSecret;
|
||||||
|
|
||||||
|
protected CachedKeyRing(long masterKeyId, int keySize, boolean isRevoked,
|
||||||
|
boolean canCertify, long creation, long expiry, int algorithm,
|
||||||
|
byte[] fingerprint, String userId, int verified, boolean hasSecret)
|
||||||
|
{
|
||||||
|
mMasterKeyId = masterKeyId;
|
||||||
|
mKeySize = keySize;
|
||||||
|
mIsRevoked = isRevoked;
|
||||||
|
mCanCertify = canCertify;
|
||||||
|
mCreation = creation;
|
||||||
|
mExpiry = expiry;
|
||||||
|
mAlgorithm = algorithm;
|
||||||
|
mFingerprint = fingerprint;
|
||||||
|
mUserId = userId;
|
||||||
|
mVerified = verified;
|
||||||
|
mHasSecret = hasSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRevoked() {
|
||||||
|
return mIsRevoked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getFingerprint() {
|
||||||
|
|
||||||
|
return mFingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrimaryUserId() {
|
||||||
|
return mUserId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMasterKeyId() {
|
||||||
|
return mMasterKeyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVerified() {
|
||||||
|
return mVerified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSignature(PGPSignature sig) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPException;
|
||||||
|
import org.spongycastle.openpgp.PGPOnePassSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
|
||||||
|
public class CachedPublicKey {
|
||||||
|
|
||||||
|
// this is the parent key ring
|
||||||
|
private final CachedPublicKeyRing mRing;
|
||||||
|
|
||||||
|
private final PGPPublicKey mKey;
|
||||||
|
|
||||||
|
CachedPublicKey(CachedPublicKeyRing ring, PGPPublicKey key) {
|
||||||
|
mRing = ring;
|
||||||
|
mKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedPublicKeyRing getKeyRing() {
|
||||||
|
return mRing;
|
||||||
|
}
|
||||||
|
|
||||||
|
JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() {
|
||||||
|
return new JcePublicKeyKeyEncryptionMethodGenerator(mKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSignature(PGPSignature sig) throws PGPException {
|
||||||
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
sig.init(contentVerifierBuilderProvider, mKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSignature(PGPOnePassSignature sig) throws PGPException {
|
||||||
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
sig.init(contentVerifierBuilderProvider, mKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getFingerprint() {
|
||||||
|
return mKey.getFingerprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this method has package visibility - no access outside the pgp package!
|
||||||
|
PGPPublicKey getKey() {
|
||||||
|
return mKey;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,219 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.bcpg.ArmoredOutputStream;
|
||||||
|
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||||
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
|
import org.spongycastle.openpgp.PGPException;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureList;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class CachedPublicKeyRing extends CachedKeyRing {
|
||||||
|
|
||||||
|
private PGPPublicKeyRing mRing;
|
||||||
|
private final byte[] mPubKey;
|
||||||
|
|
||||||
|
public CachedPublicKeyRing(long masterKeyId, int keySize, boolean isRevoked,
|
||||||
|
boolean canCertify, long creation, long expiry, int algorithm,
|
||||||
|
byte[] fingerprint, String userId, int verified, boolean hasSecret,
|
||||||
|
byte[] pubkey)
|
||||||
|
{
|
||||||
|
super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry,
|
||||||
|
algorithm, fingerprint, userId, verified, hasSecret);
|
||||||
|
|
||||||
|
mPubKey = pubkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PGPPublicKeyRing getRing() {
|
||||||
|
if(mRing == null) {
|
||||||
|
mRing = (PGPPublicKeyRing) PgpConversionHelper.BytesToPGPKeyRing(mPubKey);
|
||||||
|
}
|
||||||
|
return mRing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode(ArmoredOutputStream stream) throws IOException {
|
||||||
|
getRing().encode(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedPublicKey getSubkey(long id) {
|
||||||
|
return new CachedPublicKey(this, getRing().getPublicKey(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedPublicKey getFirstEncryptSubkey() throws PgpGeneralException {
|
||||||
|
// only return master key if no other encryption key is available
|
||||||
|
PGPPublicKey masterKey = null;
|
||||||
|
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(getRing().getPublicKeys())) {
|
||||||
|
if (key.isRevoked() || !isEncryptionKey(key) || isExpired(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (key.isMasterKey()) {
|
||||||
|
masterKey = key;
|
||||||
|
} else {
|
||||||
|
return new CachedPublicKey(this, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(masterKey == null) {
|
||||||
|
// TODO proper exception
|
||||||
|
throw new PgpGeneralException("key not found");
|
||||||
|
}
|
||||||
|
return new CachedPublicKey(this, masterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) {
|
||||||
|
boolean validSubkeyBinding = false;
|
||||||
|
boolean validTempSubkeyBinding = false;
|
||||||
|
boolean validPrimaryKeyBinding = false;
|
||||||
|
|
||||||
|
PGPPublicKey masterKey = getRing().getPublicKey();
|
||||||
|
PGPPublicKey subKey = cachedSubkey.getKey();
|
||||||
|
|
||||||
|
// Is this the master key? Match automatically, then.
|
||||||
|
if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
|
Iterator<PGPSignature> itr = subKey.getSignatures();
|
||||||
|
|
||||||
|
while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
|
||||||
|
//gpg has an invalid subkey binding error on key import I think, but doesn't shout
|
||||||
|
//about keys without subkey signing. Can't get it to import a slightly broken one
|
||||||
|
//either, so we will err on bad subkey binding here.
|
||||||
|
PGPSignature sig = itr.next();
|
||||||
|
if (sig.getKeyID() == masterKey.getKeyID() &&
|
||||||
|
sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
||||||
|
//check and if ok, check primary key binding.
|
||||||
|
try {
|
||||||
|
sig.init(contentVerifierBuilderProvider, masterKey);
|
||||||
|
validTempSubkeyBinding = sig.verifyCertification(masterKey, subKey);
|
||||||
|
} catch (PGPException e) {
|
||||||
|
continue;
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validTempSubkeyBinding) {
|
||||||
|
validSubkeyBinding = true;
|
||||||
|
}
|
||||||
|
if (validTempSubkeyBinding) {
|
||||||
|
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
|
||||||
|
masterKey, subKey);
|
||||||
|
if (validPrimaryKeyBinding) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
|
||||||
|
masterKey, subKey);
|
||||||
|
if (validPrimaryKeyBinding) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return validSubkeyBinding && validPrimaryKeyBinding;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static boolean isEncryptionKey(PGPPublicKey key) {
|
||||||
|
if (!key.isEncryptionKey()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.getVersion() <= 3) {
|
||||||
|
// this must be true now
|
||||||
|
return key.isEncryptionKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
// special cases
|
||||||
|
if (key.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
|
||||||
|
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
|
||||||
|
|
||||||
|
if (hashed != null
|
||||||
|
&& (hashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
|
||||||
|
|
||||||
|
if (unhashed != null
|
||||||
|
&& (unhashed.getKeyFlags() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isExpired(PGPPublicKey key) {
|
||||||
|
Date creationDate = key.getCreationTime();
|
||||||
|
Date expiryDate = key.getValidSeconds() > 0
|
||||||
|
? new Date(creationDate.getTime() + key.getValidSeconds() * 1000) : null;
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
|
||||||
|
PGPPublicKey masterPublicKey,
|
||||||
|
PGPPublicKey signingPublicKey) {
|
||||||
|
boolean validPrimaryKeyBinding = false;
|
||||||
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
PGPSignatureList eSigList;
|
||||||
|
|
||||||
|
if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
||||||
|
try {
|
||||||
|
eSigList = pkts.getEmbeddedSignatures();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
} catch (PGPException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < eSigList.size(); ++j) {
|
||||||
|
PGPSignature emSig = eSigList.get(j);
|
||||||
|
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
||||||
|
try {
|
||||||
|
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
||||||
|
validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
||||||
|
if (validPrimaryKeyBinding) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (PGPException e) {
|
||||||
|
continue;
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validPrimaryKeyBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPException;
|
||||||
|
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||||
|
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
|
||||||
|
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
|
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||||
|
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
|
||||||
|
public class CachedSecretKey {
|
||||||
|
|
||||||
|
// this is the parent key ring
|
||||||
|
private final CachedSecretKeyRing mRing;
|
||||||
|
|
||||||
|
private final PGPSecretKey mKey;
|
||||||
|
private PGPPrivateKey mPrivateKey = null;
|
||||||
|
|
||||||
|
CachedSecretKey(CachedSecretKeyRing ring, PGPSecretKey key) {
|
||||||
|
mRing = ring;
|
||||||
|
mKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedSecretKeyRing getRing() {
|
||||||
|
return mRing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unlock(String passphrase) throws PgpGeneralException {
|
||||||
|
try {
|
||||||
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||||
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||||
|
mPrivateKey = mKey.extractPrivateKey(keyDecryptor);
|
||||||
|
} catch (PGPException e) {
|
||||||
|
throw new PgpGeneralException("error extracting key!", e);
|
||||||
|
}
|
||||||
|
if(mPrivateKey == null) {
|
||||||
|
throw new PgpGeneralException("error extracting key (bad passphrase?)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSignatureGenerator getSignatureGenerator(int hashAlgo, boolean cleartext)
|
||||||
|
throws PgpGeneralException {
|
||||||
|
if(mPrivateKey == null) {
|
||||||
|
throw new PrivateKeyNotUnlockedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// content signer based on signing key algorithm and chosen hash algorithm
|
||||||
|
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
||||||
|
mKey.getPublicKey().getAlgorithm(), hashAlgo)
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
|
int signatureType;
|
||||||
|
if (cleartext) {
|
||||||
|
// for sign-only ascii text
|
||||||
|
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||||
|
} else {
|
||||||
|
signatureType = PGPSignature.BINARY_DOCUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
||||||
|
signatureGenerator.init(signatureType, mPrivateKey);
|
||||||
|
|
||||||
|
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
||||||
|
spGen.setSignerUserID(false, mRing.getPrimaryUserId());
|
||||||
|
signatureGenerator.setHashedSubpackets(spGen.generate());
|
||||||
|
return signatureGenerator;
|
||||||
|
} catch(PGPException e) {
|
||||||
|
throw new PgpGeneralException("Error initializing signature!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPV3SignatureGenerator getV3SignatureGenerator(int hashAlgo, boolean cleartext)
|
||||||
|
throws PgpGeneralException {
|
||||||
|
if(mPrivateKey == null) {
|
||||||
|
throw new PrivateKeyNotUnlockedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// content signer based on signing key algorithm and chosen hash algorithm
|
||||||
|
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
||||||
|
mKey.getPublicKey().getAlgorithm(), hashAlgo)
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
|
int signatureType;
|
||||||
|
if (cleartext) {
|
||||||
|
// for sign-only ascii text
|
||||||
|
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||||
|
} else {
|
||||||
|
signatureType = PGPSignature.BINARY_DOCUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PGPV3SignatureGenerator signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
||||||
|
signatureV3Generator.init(signatureType, mPrivateKey);
|
||||||
|
return signatureV3Generator;
|
||||||
|
} catch(PGPException e) {
|
||||||
|
throw new PgpGeneralException("Error initializing signature!", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PublicKeyDataDecryptorFactory getDecryptorFactory() {
|
||||||
|
if(mPrivateKey == null) {
|
||||||
|
throw new PrivateKeyNotUnlockedException();
|
||||||
|
}
|
||||||
|
return new JcePublicKeyDataDecryptorFactoryBuilder()
|
||||||
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PrivateKeyNotUnlockedException extends RuntimeException {
|
||||||
|
// this exception is a programming error which happens when an operation which requires
|
||||||
|
// the private key is called without a previous call to unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
|
|
||||||
|
public class CachedSecretKeyRing extends CachedKeyRing {
|
||||||
|
|
||||||
|
private PGPSecretKeyRing mRing;
|
||||||
|
|
||||||
|
public CachedSecretKeyRing(long masterKeyId, int keySize, boolean isRevoked,
|
||||||
|
boolean canCertify, long creation, long expiry, int algorithm,
|
||||||
|
byte[] fingerprint, String userId, int verified, boolean hasSecret,
|
||||||
|
byte[] blob)
|
||||||
|
{
|
||||||
|
super(masterKeyId, keySize, isRevoked, canCertify, creation, expiry,
|
||||||
|
algorithm, fingerprint, userId, verified, hasSecret);
|
||||||
|
|
||||||
|
mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
CachedSecretKey getSubKey(long id) {
|
||||||
|
return new CachedSecretKey(this, mRing.getSecretKey(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This returns the subkey that should be used for signing.
|
||||||
|
* At this point, this is simply the first suitable subkey.
|
||||||
|
*/
|
||||||
|
CachedSecretKey getSigningSubKey() {
|
||||||
|
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mRing.getSecretKeys())) {
|
||||||
|
if (isSigningKey(key.getPublicKey())) {
|
||||||
|
return new CachedSecretKey(this, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO exception
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isSigningKey(PGPPublicKey key) {
|
||||||
|
if (key.getVersion() <= 3) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case
|
||||||
|
if (key.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignatures())) {
|
||||||
|
if (key.isMasterKey() && sig.getKeyID() != key.getKeyID()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
|
||||||
|
|
||||||
|
if (hashed != null && (hashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
|
||||||
|
|
||||||
|
if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.SIGN_DATA) != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,10 +18,7 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import org.spongycastle.bcpg.ArmoredInputStream;
|
import org.spongycastle.bcpg.ArmoredInputStream;
|
||||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
|
||||||
import org.spongycastle.openpgp.PGPCompressedData;
|
import org.spongycastle.openpgp.PGPCompressedData;
|
||||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||||
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
||||||
@ -31,29 +28,18 @@ import org.spongycastle.openpgp.PGPObjectFactory;
|
|||||||
import org.spongycastle.openpgp.PGPOnePassSignature;
|
import org.spongycastle.openpgp.PGPOnePassSignature;
|
||||||
import org.spongycastle.openpgp.PGPOnePassSignatureList;
|
import org.spongycastle.openpgp.PGPOnePassSignatureList;
|
||||||
import org.spongycastle.openpgp.PGPPBEEncryptedData;
|
import org.spongycastle.openpgp.PGPPBEEncryptedData;
|
||||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.spongycastle.openpgp.PGPSecretKey;
|
|
||||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.openpgp.PGPSignatureList;
|
import org.spongycastle.openpgp.PGPSignatureList;
|
||||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
|
||||||
import org.spongycastle.openpgp.PGPUtil;
|
import org.spongycastle.openpgp.PGPUtil;
|
||||||
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
||||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
|
||||||
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
||||||
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
|
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
@ -67,7 +53,6 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,7 +233,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
|
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
|
||||||
PGPPBEEncryptedData encryptedDataSymmetric = null;
|
PGPPBEEncryptedData encryptedDataSymmetric = null;
|
||||||
PGPSecretKey secretEncryptionKey = null;
|
CachedSecretKey secretEncryptionKey = null;
|
||||||
Iterator<?> it = enc.getEncryptedDataObjects();
|
Iterator<?> it = enc.getEncryptedDataObjects();
|
||||||
boolean asymmetricPacketFound = false;
|
boolean asymmetricPacketFound = false;
|
||||||
boolean symmetricPacketFound = false;
|
boolean symmetricPacketFound = false;
|
||||||
@ -260,15 +245,13 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||||
|
|
||||||
long masterKeyId;
|
CachedSecretKeyRing secretKeyRing;
|
||||||
PGPSecretKeyRing secretKeyRing;
|
|
||||||
try {
|
try {
|
||||||
// get master key id for this encryption key id
|
|
||||||
masterKeyId = mProviderHelper.getMasterKeyId(
|
|
||||||
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID()))
|
|
||||||
);
|
|
||||||
// get actual keyring object based on master key id
|
// get actual keyring object based on master key id
|
||||||
secretKeyRing = mProviderHelper.getPGPSecretKeyRing(masterKeyId);
|
secretKeyRing = mProviderHelper.getCachedSecretKeyRing(
|
||||||
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||||
|
Long.toString(encData.getKeyID()))
|
||||||
|
);
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
// continue with the next packet in the while loop
|
// continue with the next packet in the while loop
|
||||||
continue;
|
continue;
|
||||||
@ -278,13 +261,14 @@ public class PgpDecryptVerify {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// get subkey which has been used for this encryption packet
|
// get subkey which has been used for this encryption packet
|
||||||
secretEncryptionKey = secretKeyRing.getSecretKey(encData.getKeyID());
|
secretEncryptionKey = secretKeyRing.getSubKey(encData.getKeyID());
|
||||||
if (secretEncryptionKey == null) {
|
if (secretEncryptionKey == null) {
|
||||||
// continue with the next packet in the while loop
|
// continue with the next packet in the while loop
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* secret key exists in database! */
|
/* secret key exists in database! */
|
||||||
|
long masterKeyId = secretEncryptionKey.getRing().getMasterKeyId();
|
||||||
|
|
||||||
// allow only specific keys for decryption?
|
// allow only specific keys for decryption?
|
||||||
if (mAllowedKeyIds != null) {
|
if (mAllowedKeyIds != null) {
|
||||||
@ -359,23 +343,15 @@ public class PgpDecryptVerify {
|
|||||||
} else if (asymmetricPacketFound) {
|
} else if (asymmetricPacketFound) {
|
||||||
currentProgress += 5;
|
currentProgress += 5;
|
||||||
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
|
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
|
||||||
PGPPrivateKey privateKey;
|
|
||||||
try {
|
try {
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
secretEncryptionKey.unlock(mPassphrase);
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
} catch (PgpGeneralException e) {
|
||||||
mPassphrase.toCharArray());
|
|
||||||
privateKey = secretEncryptionKey.extractPrivateKey(keyDecryptor);
|
|
||||||
} catch (PGPException e) {
|
|
||||||
throw new WrongPassphraseException();
|
throw new WrongPassphraseException();
|
||||||
}
|
}
|
||||||
if (privateKey == null) {
|
|
||||||
throw new KeyExtractionException();
|
|
||||||
}
|
|
||||||
currentProgress += 5;
|
currentProgress += 5;
|
||||||
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
||||||
|
|
||||||
PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
|
PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory();
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
|
|
||||||
|
|
||||||
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
||||||
|
|
||||||
@ -388,10 +364,9 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
||||||
Object dataChunk = plainFact.nextObject();
|
Object dataChunk = plainFact.nextObject();
|
||||||
PGPOnePassSignature signature = null;
|
|
||||||
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
|
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
|
||||||
PGPPublicKey signatureKey = null;
|
|
||||||
int signatureIndex = -1;
|
int signatureIndex = -1;
|
||||||
|
CachedPublicKey signingKey = null;
|
||||||
|
|
||||||
if (dataChunk instanceof PGPCompressedData) {
|
if (dataChunk instanceof PGPCompressedData) {
|
||||||
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
|
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
|
||||||
@ -403,6 +378,8 @@ public class PgpDecryptVerify {
|
|||||||
currentProgress += 10;
|
currentProgress += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PGPOnePassSignature signature = null;
|
||||||
|
|
||||||
if (dataChunk instanceof PGPOnePassSignatureList) {
|
if (dataChunk instanceof PGPOnePassSignatureList) {
|
||||||
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
||||||
|
|
||||||
@ -410,19 +387,15 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
// go through all signatures
|
// go through all signatures
|
||||||
// and find out for which signature we have a key in our database
|
// and find out for which signature we have a key in our database
|
||||||
Long masterKeyId = null;
|
|
||||||
String primaryUserId = null;
|
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
long sigKeyId = sigList.get(i).getKeyID();
|
||||||
Long.toString(sigList.get(i).getKeyID()));
|
CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing(
|
||||||
Map<String, Object> data = mProviderHelper.getGenericData(uri,
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
|
Long.toString(sigKeyId)
|
||||||
new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
|
)
|
||||||
ProviderHelper.FIELD_TYPE_STRING }
|
|
||||||
);
|
);
|
||||||
masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
|
signingKey = signingRing.getSubkey(sigKeyId);
|
||||||
primaryUserId = (String) data.get(KeyRings.USER_ID);
|
|
||||||
signatureIndex = i;
|
signatureIndex = i;
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
Log.d(Constants.TAG, "key not found!");
|
Log.d(Constants.TAG, "key not found!");
|
||||||
@ -430,43 +403,17 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (masterKeyId != null) {
|
if (signingKey != null) {
|
||||||
// key found in our database!
|
// key found in our database!
|
||||||
signature = sigList.get(signatureIndex);
|
signature = sigList.get(signatureIndex);
|
||||||
|
|
||||||
PGPPublicKeyRing publicKeyRing = null;
|
|
||||||
try {
|
|
||||||
publicKeyRing = mProviderHelper
|
|
||||||
.getPGPPublicKeyRing(masterKeyId);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
// can't happen
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the subkey which has been used to generate this signature
|
|
||||||
signatureKey = publicKeyRing.getPublicKey(signature.getKeyID());
|
|
||||||
|
|
||||||
signatureResultBuilder.signatureAvailable(true);
|
signatureResultBuilder.signatureAvailable(true);
|
||||||
signatureResultBuilder.knownKey(true);
|
signatureResultBuilder.knownKey(true);
|
||||||
signatureResultBuilder.userId(primaryUserId);
|
signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId());
|
||||||
signatureResultBuilder.keyId(masterKeyId);
|
signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId());
|
||||||
|
signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0);
|
||||||
|
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
signingKey.initSignature(signature);
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
|
||||||
signature.init(contentVerifierBuilderProvider, signatureKey);
|
|
||||||
|
|
||||||
// get certification status of this key
|
|
||||||
boolean isSignatureKeyCertified;
|
|
||||||
try {
|
|
||||||
Object data = mProviderHelper.getGenericData(
|
|
||||||
KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)),
|
|
||||||
KeyRings.VERIFIED,
|
|
||||||
ProviderHelper.FIELD_TYPE_INTEGER);
|
|
||||||
isSignatureKeyCertified = ((Long) data > 0);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
isSignatureKeyCertified = false;
|
|
||||||
}
|
|
||||||
signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified);
|
|
||||||
} else {
|
} else {
|
||||||
// no key in our database -> return "unknown pub key" status including the first key id
|
// no key in our database -> return "unknown pub key" status including the first key id
|
||||||
if (!sigList.isEmpty()) {
|
if (!sigList.isEmpty()) {
|
||||||
@ -541,7 +488,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
// Verify signature and check binding signatures
|
// Verify signature and check binding signatures
|
||||||
boolean validSignature = signature.verify(messageSignature);
|
boolean validSignature = signature.verify(messageSignature);
|
||||||
boolean validKeyBinding = verifyKeyBinding(messageSignature, signatureKey);
|
boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey);
|
||||||
|
|
||||||
signatureResultBuilder.validSignature(validSignature);
|
signatureResultBuilder.validSignature(validSignature);
|
||||||
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
||||||
@ -617,22 +564,20 @@ public class PgpDecryptVerify {
|
|||||||
throw new InvalidDataException();
|
throw new InvalidDataException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CachedPublicKey signingKey = null;
|
||||||
|
int signatureIndex = -1;
|
||||||
|
|
||||||
// go through all signatures
|
// go through all signatures
|
||||||
// and find out for which signature we have a key in our database
|
// and find out for which signature we have a key in our database
|
||||||
Long masterKeyId = null;
|
|
||||||
String primaryUserId = null;
|
|
||||||
int signatureIndex = 0;
|
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
long sigKeyId = sigList.get(i).getKeyID();
|
||||||
Long.toString(sigList.get(i).getKeyID()));
|
CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing(
|
||||||
Map<String, Object> data = mProviderHelper.getGenericData(uri,
|
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
|
Long.toString(sigKeyId)
|
||||||
new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
|
)
|
||||||
ProviderHelper.FIELD_TYPE_STRING }
|
|
||||||
);
|
);
|
||||||
masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
|
signingKey = signingRing.getSubkey(sigKeyId);
|
||||||
primaryUserId = (String) data.get(KeyRings.USER_ID);
|
|
||||||
signatureIndex = i;
|
signatureIndex = i;
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
Log.d(Constants.TAG, "key not found!");
|
Log.d(Constants.TAG, "key not found!");
|
||||||
@ -641,44 +586,18 @@ public class PgpDecryptVerify {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PGPSignature signature = null;
|
PGPSignature signature = null;
|
||||||
PGPPublicKey signatureKey = null;
|
|
||||||
if (masterKeyId != null) {
|
if (signingKey != null) {
|
||||||
// key found in our database!
|
// key found in our database!
|
||||||
signature = sigList.get(signatureIndex);
|
signature = sigList.get(signatureIndex);
|
||||||
|
|
||||||
PGPPublicKeyRing publicKeyRing = null;
|
|
||||||
try {
|
|
||||||
publicKeyRing = mProviderHelper
|
|
||||||
.getPGPPublicKeyRing(masterKeyId);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
// can't happen
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the subkey which has been used to generate this signature
|
|
||||||
signatureKey = publicKeyRing.getPublicKey(signature.getKeyID());
|
|
||||||
|
|
||||||
signatureResultBuilder.signatureAvailable(true);
|
signatureResultBuilder.signatureAvailable(true);
|
||||||
signatureResultBuilder.knownKey(true);
|
signatureResultBuilder.knownKey(true);
|
||||||
signatureResultBuilder.userId(primaryUserId);
|
signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId());
|
||||||
signatureResultBuilder.keyId(masterKeyId);
|
signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId());
|
||||||
|
signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0);
|
||||||
|
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
signingKey.initSignature(signature);
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
|
||||||
signature.init(contentVerifierBuilderProvider, signatureKey);
|
|
||||||
|
|
||||||
// get certification status of this key
|
|
||||||
boolean isSignatureKeyCertified;
|
|
||||||
try {
|
|
||||||
Object data = mProviderHelper.getGenericData(
|
|
||||||
KeychainContract.KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)),
|
|
||||||
KeyRings.VERIFIED,
|
|
||||||
ProviderHelper.FIELD_TYPE_INTEGER);
|
|
||||||
isSignatureKeyCertified = ((Long) data > 0);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
isSignatureKeyCertified = false;
|
|
||||||
}
|
|
||||||
signatureResultBuilder.signatureKeyCertified(isSignatureKeyCertified);
|
|
||||||
} else {
|
} else {
|
||||||
// no key in our database -> return "unknown pub key" status including the first key id
|
// no key in our database -> return "unknown pub key" status including the first key id
|
||||||
if (!sigList.isEmpty()) {
|
if (!sigList.isEmpty()) {
|
||||||
@ -710,7 +629,7 @@ public class PgpDecryptVerify {
|
|||||||
|
|
||||||
// Verify signature and check binding signatures
|
// Verify signature and check binding signatures
|
||||||
boolean validSignature = signature.verify();
|
boolean validSignature = signature.verify();
|
||||||
boolean validKeyBinding = verifyKeyBinding(signature, signatureKey);
|
boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey);
|
||||||
|
|
||||||
signatureResultBuilder.validSignature(validSignature);
|
signatureResultBuilder.validSignature(validSignature);
|
||||||
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
||||||
@ -722,113 +641,6 @@ public class PgpDecryptVerify {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean verifyKeyBinding(PGPSignature signature, PGPPublicKey signatureKey) {
|
|
||||||
long signatureKeyId = signature.getKeyID();
|
|
||||||
boolean validKeyBinding = false;
|
|
||||||
|
|
||||||
PGPPublicKey mKey = null;
|
|
||||||
try {
|
|
||||||
PGPPublicKeyRing signKeyRing = mProviderHelper.getPGPPublicKeyRingWithKeyId(
|
|
||||||
signatureKeyId);
|
|
||||||
mKey = signKeyRing.getPublicKey();
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
|
||||||
Log.d(Constants.TAG, "key not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signature.getKeyID() != mKey.getKeyID()) {
|
|
||||||
validKeyBinding = verifyKeyBinding(mKey, signatureKey);
|
|
||||||
} else { //if the key used to make the signature was the master key, no need to check binding sigs
|
|
||||||
validKeyBinding = true;
|
|
||||||
}
|
|
||||||
return validKeyBinding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
|
||||||
boolean validSubkeyBinding = false;
|
|
||||||
boolean validTempSubkeyBinding = false;
|
|
||||||
boolean validPrimaryKeyBinding = false;
|
|
||||||
|
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
|
||||||
|
|
||||||
Iterator<PGPSignature> itr = signingPublicKey.getSignatures();
|
|
||||||
|
|
||||||
while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong?
|
|
||||||
//gpg has an invalid subkey binding error on key import I think, but doesn't shout
|
|
||||||
//about keys without subkey signing. Can't get it to import a slightly broken one
|
|
||||||
//either, so we will err on bad subkey binding here.
|
|
||||||
PGPSignature sig = itr.next();
|
|
||||||
if (sig.getKeyID() == masterPublicKey.getKeyID() &&
|
|
||||||
sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
|
||||||
//check and if ok, check primary key binding.
|
|
||||||
try {
|
|
||||||
sig.init(contentVerifierBuilderProvider, masterPublicKey);
|
|
||||||
validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey);
|
|
||||||
} catch (PGPException e) {
|
|
||||||
continue;
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validTempSubkeyBinding) {
|
|
||||||
validSubkeyBinding = true;
|
|
||||||
}
|
|
||||||
if (validTempSubkeyBinding) {
|
|
||||||
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(),
|
|
||||||
masterPublicKey, signingPublicKey);
|
|
||||||
if (validPrimaryKeyBinding) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(),
|
|
||||||
masterPublicKey, signingPublicKey);
|
|
||||||
if (validPrimaryKeyBinding) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (validSubkeyBinding & validPrimaryKeyBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector pkts,
|
|
||||||
PGPPublicKey masterPublicKey,
|
|
||||||
PGPPublicKey signingPublicKey) {
|
|
||||||
boolean validPrimaryKeyBinding = false;
|
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
|
||||||
PGPSignatureList eSigList;
|
|
||||||
|
|
||||||
if (pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
|
||||||
try {
|
|
||||||
eSigList = pkts.getEmbeddedSignatures();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
} catch (PGPException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < eSigList.size(); ++j) {
|
|
||||||
PGPSignature emSig = eSigList.get(j);
|
|
||||||
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
|
||||||
try {
|
|
||||||
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
|
||||||
validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
|
||||||
if (validPrimaryKeyBinding) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (PGPException e) {
|
|
||||||
continue;
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validPrimaryKeyBinding;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mostly taken from ClearSignedFileProcessor in Bouncy Castle
|
* Mostly taken from ClearSignedFileProcessor in Bouncy Castle
|
||||||
*
|
*
|
||||||
|
@ -32,8 +32,8 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
|
|||||||
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||||
@ -208,9 +208,11 @@ public class PgpImportExport {
|
|||||||
updateProgress(progress * 100 / masterKeyIdsSize, 100);
|
updateProgress(progress * 100 / masterKeyIdsSize, 100);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PGPPublicKeyRing publicKeyRing = mProviderHelper.getPGPPublicKeyRing(pubKeyMasterId);
|
CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(
|
||||||
|
KeychainContract.KeyRings.buildGenericKeyRingUri(pubKeyMasterId)
|
||||||
|
);
|
||||||
|
|
||||||
publicKeyRing.encode(arOutStream);
|
ring.encode(arOutStream);
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
Log.e(Constants.TAG, "key not found!", e);
|
||||||
// TODO: inform user?
|
// TODO: inform user?
|
||||||
|
@ -52,14 +52,17 @@ public class PgpKeyHelper {
|
|||||||
|
|
||||||
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
|
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Date getCreationDate(PGPPublicKey key) {
|
public static Date getCreationDate(PGPPublicKey key) {
|
||||||
return key.getCreationTime();
|
return key.getCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Date getCreationDate(PGPSecretKey key) {
|
public static Date getCreationDate(PGPSecretKey key) {
|
||||||
return key.getPublicKey().getCreationTime();
|
return key.getPublicKey().getCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Date getExpiryDate(PGPPublicKey key) {
|
public static Date getExpiryDate(PGPPublicKey key) {
|
||||||
Date creationDate = getCreationDate(key);
|
Date creationDate = getCreationDate(key);
|
||||||
if (key.getValidDays() == 0) {
|
if (key.getValidDays() == 0) {
|
||||||
@ -73,10 +76,12 @@ public class PgpKeyHelper {
|
|||||||
return calendar.getTime();
|
return calendar.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Date getExpiryDate(PGPSecretKey key) {
|
public static Date getExpiryDate(PGPSecretKey key) {
|
||||||
return getExpiryDate(key.getPublicKey());
|
return getExpiryDate(key.getPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static boolean isExpired(PGPPublicKey key) {
|
public static boolean isExpired(PGPPublicKey key) {
|
||||||
Date creationDate = getCreationDate(key);
|
Date creationDate = getCreationDate(key);
|
||||||
Date expiryDate = getExpiryDate(key);
|
Date expiryDate = getExpiryDate(key);
|
||||||
@ -89,6 +94,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
|
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
|
||||||
long cnt = 0;
|
long cnt = 0;
|
||||||
if (keyRing == null) {
|
if (keyRing == null) {
|
||||||
@ -105,6 +111,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
private static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
|
private static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
|
||||||
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
|
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
|
||||||
|
|
||||||
@ -118,6 +125,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
private static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
|
private static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
|
||||||
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
||||||
|
|
||||||
@ -131,6 +139,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
private static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
|
private static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
|
||||||
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
||||||
|
|
||||||
@ -143,26 +152,7 @@ public class PgpKeyHelper {
|
|||||||
return signingKeys;
|
return signingKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
|
@Deprecated
|
||||||
Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>();
|
|
||||||
Vector<PGPPublicKey> encryptKeys = getEncryptKeys(keyRing);
|
|
||||||
PGPPublicKey masterKey = null;
|
|
||||||
for (int i = 0; i < encryptKeys.size(); ++i) {
|
|
||||||
PGPPublicKey key = encryptKeys.get(i);
|
|
||||||
if (!isExpired(key) && !key.isRevoked()) {
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
masterKey = key;
|
|
||||||
} else {
|
|
||||||
usableKeys.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (masterKey != null) {
|
|
||||||
usableKeys.add(masterKey);
|
|
||||||
}
|
|
||||||
return usableKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
|
private static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
|
||||||
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
||||||
Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
|
Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
|
||||||
@ -181,6 +171,7 @@ public class PgpKeyHelper {
|
|||||||
return usableKeys;
|
return usableKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
private static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
|
private static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
|
||||||
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
||||||
Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
|
Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
|
||||||
@ -199,16 +190,6 @@ public class PgpKeyHelper {
|
|||||||
return usableKeys;
|
return usableKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static PGPPublicKey getFirstEncryptSubkey(PGPPublicKeyRing keyRing) {
|
|
||||||
Vector<PGPPublicKey> encryptKeys = getUsableEncryptKeys(keyRing);
|
|
||||||
if (encryptKeys.size() == 0) {
|
|
||||||
Log.e(Constants.TAG, "encryptKeys is null!");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return encryptKeys.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PGPSecretKey getFirstCertificationSubkey(PGPSecretKeyRing keyRing) {
|
public static PGPSecretKey getFirstCertificationSubkey(PGPSecretKeyRing keyRing) {
|
||||||
Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
|
Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
|
||||||
if (signingKeys.size() == 0) {
|
if (signingKeys.size() == 0) {
|
||||||
@ -253,6 +234,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
public static boolean isEncryptionKey(PGPPublicKey key) {
|
public static boolean isEncryptionKey(PGPPublicKey key) {
|
||||||
if (!key.isEncryptionKey()) {
|
if (!key.isEncryptionKey()) {
|
||||||
return false;
|
return false;
|
||||||
@ -298,6 +280,7 @@ public class PgpKeyHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
public static boolean isSigningKey(PGPPublicKey key) {
|
public static boolean isSigningKey(PGPPublicKey key) {
|
||||||
if (key.getVersion() <= 3) {
|
if (key.getVersion() <= 3) {
|
||||||
return true;
|
return true;
|
||||||
@ -328,11 +311,13 @@ public class PgpKeyHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static boolean isSigningKey(PGPSecretKey key) {
|
public static boolean isSigningKey(PGPSecretKey key) {
|
||||||
return isSigningKey(key.getPublicKey());
|
return isSigningKey(key.getPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
public static boolean isCertificationKey(PGPPublicKey key) {
|
public static boolean isCertificationKey(PGPPublicKey key) {
|
||||||
if (key.getVersion() <= 3) {
|
if (key.getVersion() <= 3) {
|
||||||
return true;
|
return true;
|
||||||
@ -358,11 +343,13 @@ public class PgpKeyHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static boolean isAuthenticationKey(PGPSecretKey key) {
|
public static boolean isAuthenticationKey(PGPSecretKey key) {
|
||||||
return isAuthenticationKey(key.getPublicKey());
|
return isAuthenticationKey(key.getPublicKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@Deprecated
|
||||||
public static boolean isAuthenticationKey(PGPPublicKey key) {
|
public static boolean isAuthenticationKey(PGPPublicKey key) {
|
||||||
if (key.getVersion() <= 3) {
|
if (key.getVersion() <= 3) {
|
||||||
return true;
|
return true;
|
||||||
@ -388,6 +375,7 @@ public class PgpKeyHelper {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static boolean isCertificationKey(PGPSecretKey key) {
|
public static boolean isCertificationKey(PGPSecretKey key) {
|
||||||
return isCertificationKey(key.getPublicKey());
|
return isCertificationKey(key.getPublicKey());
|
||||||
}
|
}
|
||||||
|
@ -25,25 +25,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
|
|||||||
import org.spongycastle.openpgp.PGPException;
|
import org.spongycastle.openpgp.PGPException;
|
||||||
import org.spongycastle.openpgp.PGPLiteralData;
|
import org.spongycastle.openpgp.PGPLiteralData;
|
||||||
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
|
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
|
||||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.spongycastle.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.spongycastle.openpgp.PGPSecretKey;
|
|
||||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
|
||||||
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
import org.spongycastle.openpgp.PGPSignatureGenerator;
|
||||||
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
|
|
||||||
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
|
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
|
||||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
|
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
|
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@ -279,19 +268,15 @@ public class PgpSignEncrypt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get keys for signature generation for later usage */
|
/* Get keys for signature generation for later usage */
|
||||||
PGPSecretKey signingKey = null;
|
CachedSecretKey signingKey = null;
|
||||||
PGPSecretKeyRing signingKeyRing = null;
|
|
||||||
PGPPrivateKey signaturePrivateKey = null;
|
|
||||||
String signingUserId = null;
|
|
||||||
if (enableSignature) {
|
if (enableSignature) {
|
||||||
|
CachedSecretKeyRing signingKeyRing = null;
|
||||||
try {
|
try {
|
||||||
signingKeyRing = mProviderHelper.getPGPSecretKeyRing(mSignatureMasterKeyId);
|
signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId);
|
||||||
signingUserId = (String) mProviderHelper.getUnifiedData(mSignatureMasterKeyId,
|
|
||||||
KeychainContract.KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING);
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
throw new NoSigningKeyException();
|
throw new NoSigningKeyException();
|
||||||
}
|
}
|
||||||
signingKey = PgpKeyHelper.getFirstSigningSubkey(signingKeyRing);
|
signingKey = signingKeyRing.getSigningSubKey();
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
throw new NoSigningKeyException();
|
throw new NoSigningKeyException();
|
||||||
}
|
}
|
||||||
@ -302,10 +287,9 @@ public class PgpSignEncrypt {
|
|||||||
|
|
||||||
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
|
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
|
||||||
|
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
try {
|
||||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
|
signingKey.unlock(mSignaturePassphrase);
|
||||||
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
|
} catch (PgpGeneralException e) {
|
||||||
if (signaturePrivateKey == null) {
|
|
||||||
throw new KeyExtractionException();
|
throw new KeyExtractionException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,13 +317,12 @@ public class PgpSignEncrypt {
|
|||||||
// Asymmetric encryption
|
// Asymmetric encryption
|
||||||
for (long id : mEncryptionMasterKeyIds) {
|
for (long id : mEncryptionMasterKeyIds) {
|
||||||
try {
|
try {
|
||||||
PGPPublicKeyRing keyRing = mProviderHelper.getPGPPublicKeyRing(id);
|
CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing(
|
||||||
PGPPublicKey key = PgpKeyHelper.getFirstEncryptSubkey(keyRing);
|
KeyRings.buildUnifiedKeyRingUri(Long.toString(id)));
|
||||||
if (key != null) {
|
CachedPublicKey key = keyRing.getFirstEncryptSubkey();
|
||||||
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
|
cPk.addMethod(key.getPubKeyEncryptionGenerator());
|
||||||
new JcePublicKeyKeyEncryptionMethodGenerator(key);
|
} catch (PgpGeneralException e) {
|
||||||
cPk.addMethod(pubKeyEncryptionGenerator);
|
Log.e(Constants.TAG, "key not found!", e);
|
||||||
}
|
|
||||||
} catch (ProviderHelper.NotFoundException e) {
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
Log.e(Constants.TAG, "key not found!", e);
|
Log.e(Constants.TAG, "key not found!", e);
|
||||||
}
|
}
|
||||||
@ -353,29 +336,18 @@ public class PgpSignEncrypt {
|
|||||||
if (enableSignature) {
|
if (enableSignature) {
|
||||||
updateProgress(R.string.progress_preparing_signature, 10, 100);
|
updateProgress(R.string.progress_preparing_signature, 10, 100);
|
||||||
|
|
||||||
// content signer based on signing key algorithm and chosen hash algorithm
|
try {
|
||||||
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption;
|
||||||
signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
|
if (mSignatureForceV3) {
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
signatureV3Generator = signingKey.getV3SignatureGenerator(
|
||||||
|
mSignatureHashAlgorithm,cleartext);
|
||||||
int signatureType;
|
} else {
|
||||||
if (mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption) {
|
signatureGenerator = signingKey.getSignatureGenerator(
|
||||||
// for sign-only ascii text
|
mSignatureHashAlgorithm, cleartext);
|
||||||
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
}
|
||||||
} else {
|
} catch (PgpGeneralException e) {
|
||||||
signatureType = PGPSignature.BINARY_DOCUMENT;
|
// TODO throw correct type of exception (which shouldn't be PGPException)
|
||||||
}
|
throw new KeyExtractionException();
|
||||||
|
|
||||||
if (mSignatureForceV3) {
|
|
||||||
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
|
||||||
signatureV3Generator.init(signatureType, signaturePrivateKey);
|
|
||||||
} else {
|
|
||||||
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
|
||||||
signatureGenerator.init(signatureType, signaturePrivateKey);
|
|
||||||
|
|
||||||
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
|
||||||
spGen.setSignerUserID(false, signingUserId);
|
|
||||||
signatureGenerator.setHashedSubpackets(spGen.generate());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,8 @@ public class KeychainContract {
|
|||||||
public static final String HAS_ANY_SECRET = "has_any_secret";
|
public static final String HAS_ANY_SECRET = "has_any_secret";
|
||||||
public static final String HAS_ENCRYPT = "has_encrypt";
|
public static final String HAS_ENCRYPT = "has_encrypt";
|
||||||
public static final String HAS_SIGN = "has_sign";
|
public static final String HAS_SIGN = "has_sign";
|
||||||
|
public static final String PUBKEY_DATA = "pubkey_data";
|
||||||
|
public static final String PRIVKEY_DATA = "privkey_data";
|
||||||
|
|
||||||
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
|
||||||
.appendPath(BASE_KEY_RINGS).build();
|
.appendPath(BASE_KEY_RINGS).build();
|
||||||
@ -123,6 +125,10 @@ public class KeychainContract {
|
|||||||
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
|
return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Uri buildGenericKeyRingUri(long masterKeyId) {
|
||||||
|
return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).build();
|
||||||
|
}
|
||||||
|
|
||||||
public static Uri buildGenericKeyRingUri(String masterKeyId) {
|
public static Uri buildGenericKeyRingUri(String masterKeyId) {
|
||||||
return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
|
return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
|
||||||
}
|
}
|
||||||
|
@ -254,6 +254,12 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
|
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
|
||||||
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
|
||||||
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED);
|
||||||
|
projectionMap.put(KeyRings.PUBKEY_DATA,
|
||||||
|
Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA
|
||||||
|
+ " AS " + KeyRings.PUBKEY_DATA);
|
||||||
|
projectionMap.put(KeyRings.PRIVKEY_DATA,
|
||||||
|
Tables.KEY_RINGS_SECRET + "." + KeyRingData.KEY_RING_DATA
|
||||||
|
+ " AS " + KeyRings.PRIVKEY_DATA);
|
||||||
projectionMap.put(KeyRings.HAS_SECRET, KeyRings.HAS_SECRET);
|
projectionMap.put(KeyRings.HAS_SECRET, KeyRings.HAS_SECRET);
|
||||||
projectionMap.put(KeyRings.HAS_ANY_SECRET,
|
projectionMap.put(KeyRings.HAS_ANY_SECRET,
|
||||||
"(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
|
"(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
|
||||||
@ -295,6 +301,22 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
+ " AND " + Tables.CERTS + "." + Certs.VERIFIED
|
+ " AND " + Tables.CERTS + "." + Certs.VERIFIED
|
||||||
+ " = " + Certs.VERIFIED_SECRET
|
+ " = " + Certs.VERIFIED_SECRET
|
||||||
+ ")"
|
+ ")"
|
||||||
|
// fairly expensive join (due to blob data), only do it when requested
|
||||||
|
+ (Arrays.asList(projection).contains(KeyRings.PUBKEY_DATA) ?
|
||||||
|
" INNER JOIN " + Tables.KEY_RINGS_PUBLIC + " ON ("
|
||||||
|
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
|
+ " = "
|
||||||
|
+ Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.MASTER_KEY_ID
|
||||||
|
+ ")"
|
||||||
|
: "")
|
||||||
|
// fairly expensive join (due to blob data), only do it when requested
|
||||||
|
+ (Arrays.asList(projection).contains(KeyRings.PRIVKEY_DATA) ?
|
||||||
|
" LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
|
||||||
|
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID
|
||||||
|
+ " = "
|
||||||
|
+ Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID
|
||||||
|
+ ")"
|
||||||
|
: "")
|
||||||
);
|
);
|
||||||
qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
|
qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
|
||||||
// in case there are multiple verifying certificates
|
// in case there are multiple verifying certificates
|
||||||
|
@ -36,9 +36,10 @@ import org.spongycastle.openpgp.PGPPublicKeyRing;
|
|||||||
import org.spongycastle.openpgp.PGPSecretKey;
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CachedSecretKeyRing;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.CachedPublicKeyRing;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||||
@ -167,6 +168,7 @@ public class ProviderHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public Map<Long, PGPKeyRing> getPGPKeyRings(Uri queryUri) {
|
public Map<Long, PGPKeyRing> getPGPKeyRings(Uri queryUri) {
|
||||||
Cursor cursor = mContentResolver.query(queryUri,
|
Cursor cursor = mContentResolver.query(queryUri,
|
||||||
new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA},
|
new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA},
|
||||||
@ -188,6 +190,94 @@ public class ProviderHelper {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CachedPublicKeyRing getCachedPublicKeyRing(Uri queryUri) throws NotFoundException {
|
||||||
|
Cursor cursor = mContentResolver.query(queryUri,
|
||||||
|
new String[] {
|
||||||
|
KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE,
|
||||||
|
KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY,
|
||||||
|
KeyRings.CREATION, KeyRings.EXPIRY,
|
||||||
|
KeyRings.ALGORITHM, KeyRings.FINGERPRINT,
|
||||||
|
KeyRings.USER_ID, KeyRings.VERIFIED,
|
||||||
|
KeyRings.HAS_SECRET, KeyRings.PUBKEY_DATA
|
||||||
|
}, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
long masterKeyId = cursor.getLong(0);
|
||||||
|
int keySize = cursor.getInt(1);
|
||||||
|
boolean isRevoked = cursor.getInt(2) > 0;
|
||||||
|
boolean canCertify = cursor.getInt(3) > 0;
|
||||||
|
long creation = cursor.getLong(4);
|
||||||
|
long expiry = cursor.getLong(5);
|
||||||
|
int algorithm = cursor.getInt(6);
|
||||||
|
byte[] fingerprint = cursor.getBlob(7);
|
||||||
|
String userId = cursor.getString(8);
|
||||||
|
int verified = cursor.getInt(9);
|
||||||
|
boolean hasSecret = cursor.getInt(10) > 0;
|
||||||
|
byte[] pubkey = cursor.getBlob(11);
|
||||||
|
return new CachedPublicKeyRing(
|
||||||
|
masterKeyId, keySize, isRevoked, canCertify,
|
||||||
|
creation, expiry, algorithm, fingerprint,
|
||||||
|
userId, verified, hasSecret, pubkey
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException("Key not found!");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedSecretKeyRing getCachedSecretKeyRing(long id) throws NotFoundException {
|
||||||
|
return getCachedSecretKeyRing(KeyRings.buildUnifiedKeyRingUri(Long.toString(id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedSecretKeyRing getCachedSecretKeyRing(Uri queryUri) throws NotFoundException {
|
||||||
|
Cursor cursor = mContentResolver.query(queryUri,
|
||||||
|
new String[] {
|
||||||
|
KeyRings.MASTER_KEY_ID, KeyRings.KEY_SIZE,
|
||||||
|
KeyRings.IS_REVOKED, KeyRings.CAN_CERTIFY,
|
||||||
|
KeyRings.CREATION, KeyRings.EXPIRY,
|
||||||
|
KeyRings.ALGORITHM, KeyRings.FINGERPRINT,
|
||||||
|
KeyRings.USER_ID, KeyRings.VERIFIED,
|
||||||
|
KeyRings.HAS_SECRET, KeyRings.PRIVKEY_DATA
|
||||||
|
}, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
// check if a privkey is actually available
|
||||||
|
byte[] privkey = cursor.getBlob(11);
|
||||||
|
if(privkey == null) {
|
||||||
|
throw new NotFoundException("Key found, but no secret key available!");
|
||||||
|
}
|
||||||
|
|
||||||
|
long masterKeyId = cursor.getLong(0);
|
||||||
|
int keySize = cursor.getInt(1);
|
||||||
|
boolean isRevoked = cursor.getInt(2) > 0;
|
||||||
|
boolean canCertify = cursor.getInt(3) > 0;
|
||||||
|
long creation = cursor.getLong(4);
|
||||||
|
long expiry = cursor.getLong(5);
|
||||||
|
int algorithm = cursor.getInt(6);
|
||||||
|
byte[] fingerprint = cursor.getBlob(7);
|
||||||
|
String userId = cursor.getString(8);
|
||||||
|
int verified = cursor.getInt(9);
|
||||||
|
boolean hasSecret = cursor.getInt(10) > 0;
|
||||||
|
return new CachedSecretKeyRing(
|
||||||
|
masterKeyId, keySize, isRevoked, canCertify,
|
||||||
|
creation, expiry, algorithm, fingerprint,
|
||||||
|
userId, verified, hasSecret, privkey
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException("Key not found!");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public PGPKeyRing getPGPKeyRing(Uri queryUri) throws NotFoundException {
|
public PGPKeyRing getPGPKeyRing(Uri queryUri) throws NotFoundException {
|
||||||
Map<Long, PGPKeyRing> result = getPGPKeyRings(queryUri);
|
Map<Long, PGPKeyRing> result = getPGPKeyRings(queryUri);
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
@ -197,6 +287,7 @@ public class ProviderHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(long keyId)
|
public PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(long keyId)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
||||||
@ -204,6 +295,7 @@ public class ProviderHelper {
|
|||||||
return getPGPPublicKeyRing(masterKeyId);
|
return getPGPPublicKeyRing(masterKeyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId)
|
public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
||||||
@ -214,6 +306,7 @@ public class ProviderHelper {
|
|||||||
/**
|
/**
|
||||||
* Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId
|
* Retrieves the actual PGPPublicKeyRing object from the database blob based on the masterKeyId
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public PGPPublicKeyRing getPGPPublicKeyRing(long masterKeyId) throws NotFoundException {
|
public PGPPublicKeyRing getPGPPublicKeyRing(long masterKeyId) throws NotFoundException {
|
||||||
Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
||||||
return (PGPPublicKeyRing) getPGPKeyRing(queryUri);
|
return (PGPPublicKeyRing) getPGPKeyRing(queryUri);
|
||||||
@ -222,6 +315,7 @@ public class ProviderHelper {
|
|||||||
/**
|
/**
|
||||||
* Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId
|
* Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public PGPSecretKeyRing getPGPSecretKeyRing(long masterKeyId) throws NotFoundException {
|
public PGPSecretKeyRing getPGPSecretKeyRing(long masterKeyId) throws NotFoundException {
|
||||||
Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||||
return (PGPSecretKeyRing) getPGPKeyRing(queryUri);
|
return (PGPSecretKeyRing) getPGPKeyRing(queryUri);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user