mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-11 03:25:05 -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;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.spongycastle.bcpg.ArmoredInputStream;
|
||||
import org.spongycastle.bcpg.SignatureSubpacketTags;
|
||||
import org.spongycastle.openpgp.PGPCompressedData;
|
||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPEncryptedDataList;
|
||||
@ -31,29 +28,18 @@ import org.spongycastle.openpgp.PGPObjectFactory;
|
||||
import org.spongycastle.openpgp.PGPOnePassSignature;
|
||||
import org.spongycastle.openpgp.PGPOnePassSignatureList;
|
||||
import org.spongycastle.openpgp.PGPPBEEncryptedData;
|
||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||
import org.spongycastle.openpgp.PGPPublicKey;
|
||||
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.PGPSignatureList;
|
||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
|
||||
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.JcePBEDataDecryptorFactoryBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
@ -67,7 +53,6 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -248,7 +233,7 @@ public class PgpDecryptVerify {
|
||||
|
||||
PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
|
||||
PGPPBEEncryptedData encryptedDataSymmetric = null;
|
||||
PGPSecretKey secretEncryptionKey = null;
|
||||
CachedSecretKey secretEncryptionKey = null;
|
||||
Iterator<?> it = enc.getEncryptedDataObjects();
|
||||
boolean asymmetricPacketFound = false;
|
||||
boolean symmetricPacketFound = false;
|
||||
@ -260,15 +245,13 @@ public class PgpDecryptVerify {
|
||||
|
||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||
|
||||
long masterKeyId;
|
||||
PGPSecretKeyRing secretKeyRing;
|
||||
CachedSecretKeyRing secretKeyRing;
|
||||
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
|
||||
secretKeyRing = mProviderHelper.getPGPSecretKeyRing(masterKeyId);
|
||||
secretKeyRing = mProviderHelper.getCachedSecretKeyRing(
|
||||
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||
Long.toString(encData.getKeyID()))
|
||||
);
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
// continue with the next packet in the while loop
|
||||
continue;
|
||||
@ -278,13 +261,14 @@ public class PgpDecryptVerify {
|
||||
continue;
|
||||
}
|
||||
// get subkey which has been used for this encryption packet
|
||||
secretEncryptionKey = secretKeyRing.getSecretKey(encData.getKeyID());
|
||||
secretEncryptionKey = secretKeyRing.getSubKey(encData.getKeyID());
|
||||
if (secretEncryptionKey == null) {
|
||||
// continue with the next packet in the while loop
|
||||
continue;
|
||||
}
|
||||
|
||||
/* secret key exists in database! */
|
||||
long masterKeyId = secretEncryptionKey.getRing().getMasterKeyId();
|
||||
|
||||
// allow only specific keys for decryption?
|
||||
if (mAllowedKeyIds != null) {
|
||||
@ -359,23 +343,15 @@ public class PgpDecryptVerify {
|
||||
} else if (asymmetricPacketFound) {
|
||||
currentProgress += 5;
|
||||
updateProgress(R.string.progress_extracting_key, currentProgress, 100);
|
||||
PGPPrivateKey privateKey;
|
||||
try {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
mPassphrase.toCharArray());
|
||||
privateKey = secretEncryptionKey.extractPrivateKey(keyDecryptor);
|
||||
} catch (PGPException e) {
|
||||
secretEncryptionKey.unlock(mPassphrase);
|
||||
} catch (PgpGeneralException e) {
|
||||
throw new WrongPassphraseException();
|
||||
}
|
||||
if (privateKey == null) {
|
||||
throw new KeyExtractionException();
|
||||
}
|
||||
currentProgress += 5;
|
||||
updateProgress(R.string.progress_preparing_streams, currentProgress, 100);
|
||||
|
||||
PublicKeyDataDecryptorFactory decryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(privateKey);
|
||||
PublicKeyDataDecryptorFactory decryptorFactory = secretEncryptionKey.getDecryptorFactory();
|
||||
|
||||
clear = encryptedDataAsymmetric.getDataStream(decryptorFactory);
|
||||
|
||||
@ -388,10 +364,9 @@ public class PgpDecryptVerify {
|
||||
|
||||
PGPObjectFactory plainFact = new PGPObjectFactory(clear);
|
||||
Object dataChunk = plainFact.nextObject();
|
||||
PGPOnePassSignature signature = null;
|
||||
OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder();
|
||||
PGPPublicKey signatureKey = null;
|
||||
int signatureIndex = -1;
|
||||
CachedPublicKey signingKey = null;
|
||||
|
||||
if (dataChunk instanceof PGPCompressedData) {
|
||||
updateProgress(R.string.progress_decompressing_data, currentProgress, 100);
|
||||
@ -403,6 +378,8 @@ public class PgpDecryptVerify {
|
||||
currentProgress += 10;
|
||||
}
|
||||
|
||||
PGPOnePassSignature signature = null;
|
||||
|
||||
if (dataChunk instanceof PGPOnePassSignatureList) {
|
||||
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
||||
|
||||
@ -410,19 +387,15 @@ public class PgpDecryptVerify {
|
||||
|
||||
// go through all signatures
|
||||
// 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) {
|
||||
try {
|
||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||
Long.toString(sigList.get(i).getKeyID()));
|
||||
Map<String, Object> data = mProviderHelper.getGenericData(uri,
|
||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
|
||||
new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
|
||||
ProviderHelper.FIELD_TYPE_STRING }
|
||||
long sigKeyId = sigList.get(i).getKeyID();
|
||||
CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing(
|
||||
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||
Long.toString(sigKeyId)
|
||||
)
|
||||
);
|
||||
masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
|
||||
primaryUserId = (String) data.get(KeyRings.USER_ID);
|
||||
signingKey = signingRing.getSubkey(sigKeyId);
|
||||
signatureIndex = i;
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
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!
|
||||
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.knownKey(true);
|
||||
signatureResultBuilder.userId(primaryUserId);
|
||||
signatureResultBuilder.keyId(masterKeyId);
|
||||
signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId());
|
||||
signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId());
|
||||
signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0);
|
||||
|
||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||
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);
|
||||
signingKey.initSignature(signature);
|
||||
} else {
|
||||
// no key in our database -> return "unknown pub key" status including the first key id
|
||||
if (!sigList.isEmpty()) {
|
||||
@ -541,7 +488,7 @@ public class PgpDecryptVerify {
|
||||
|
||||
// Verify signature and check binding signatures
|
||||
boolean validSignature = signature.verify(messageSignature);
|
||||
boolean validKeyBinding = verifyKeyBinding(messageSignature, signatureKey);
|
||||
boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey);
|
||||
|
||||
signatureResultBuilder.validSignature(validSignature);
|
||||
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
||||
@ -617,22 +564,20 @@ public class PgpDecryptVerify {
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
CachedPublicKey signingKey = null;
|
||||
int signatureIndex = -1;
|
||||
|
||||
// go through all signatures
|
||||
// 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) {
|
||||
try {
|
||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||
Long.toString(sigList.get(i).getKeyID()));
|
||||
Map<String, Object> data = mProviderHelper.getGenericData(uri,
|
||||
new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
|
||||
new int[] { ProviderHelper.FIELD_TYPE_INTEGER,
|
||||
ProviderHelper.FIELD_TYPE_STRING }
|
||||
long sigKeyId = sigList.get(i).getKeyID();
|
||||
CachedPublicKeyRing signingRing = mProviderHelper.getCachedPublicKeyRing(
|
||||
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
|
||||
Long.toString(sigKeyId)
|
||||
)
|
||||
);
|
||||
masterKeyId = (Long) data.get(KeyRings.MASTER_KEY_ID);
|
||||
primaryUserId = (String) data.get(KeyRings.USER_ID);
|
||||
signingKey = signingRing.getSubkey(sigKeyId);
|
||||
signatureIndex = i;
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
Log.d(Constants.TAG, "key not found!");
|
||||
@ -641,44 +586,18 @@ public class PgpDecryptVerify {
|
||||
}
|
||||
|
||||
PGPSignature signature = null;
|
||||
PGPPublicKey signatureKey = null;
|
||||
if (masterKeyId != null) {
|
||||
|
||||
if (signingKey != null) {
|
||||
// key found in our database!
|
||||
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.knownKey(true);
|
||||
signatureResultBuilder.userId(primaryUserId);
|
||||
signatureResultBuilder.keyId(masterKeyId);
|
||||
signatureResultBuilder.keyId(signingKey.getKeyRing().getMasterKeyId());
|
||||
signatureResultBuilder.userId(signingKey.getKeyRing().getPrimaryUserId());
|
||||
signatureResultBuilder.signatureKeyCertified(signingKey.getKeyRing().getVerified() > 0);
|
||||
|
||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||
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);
|
||||
signingKey.initSignature(signature);
|
||||
} else {
|
||||
// no key in our database -> return "unknown pub key" status including the first key id
|
||||
if (!sigList.isEmpty()) {
|
||||
@ -710,7 +629,7 @@ public class PgpDecryptVerify {
|
||||
|
||||
// Verify signature and check binding signatures
|
||||
boolean validSignature = signature.verify();
|
||||
boolean validKeyBinding = verifyKeyBinding(signature, signatureKey);
|
||||
boolean validKeyBinding = signingKey.getKeyRing().verifySubkeyBinding(signingKey);
|
||||
|
||||
signatureResultBuilder.validSignature(validSignature);
|
||||
signatureResultBuilder.validKeyBinding(validKeyBinding);
|
||||
@ -722,113 +641,6 @@ public class PgpDecryptVerify {
|
||||
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
|
||||
*
|
||||
|
@ -32,8 +32,8 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
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.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
@ -208,9 +208,11 @@ public class PgpImportExport {
|
||||
updateProgress(progress * 100 / masterKeyIdsSize, 100);
|
||||
|
||||
try {
|
||||
PGPPublicKeyRing publicKeyRing = mProviderHelper.getPGPPublicKeyRing(pubKeyMasterId);
|
||||
CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(
|
||||
KeychainContract.KeyRings.buildGenericKeyRingUri(pubKeyMasterId)
|
||||
);
|
||||
|
||||
publicKeyRing.encode(arOutStream);
|
||||
ring.encode(arOutStream);
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
Log.e(Constants.TAG, "key not found!", e);
|
||||
// TODO: inform user?
|
||||
|
@ -52,14 +52,17 @@ public class PgpKeyHelper {
|
||||
|
||||
private static final Pattern USER_ID_PATTERN = Pattern.compile("^(.*?)(?: \\((.*)\\))?(?: <(.*)>)?$");
|
||||
|
||||
@Deprecated
|
||||
public static Date getCreationDate(PGPPublicKey key) {
|
||||
return key.getCreationTime();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Date getCreationDate(PGPSecretKey key) {
|
||||
return key.getPublicKey().getCreationTime();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Date getExpiryDate(PGPPublicKey key) {
|
||||
Date creationDate = getCreationDate(key);
|
||||
if (key.getValidDays() == 0) {
|
||||
@ -73,10 +76,12 @@ public class PgpKeyHelper {
|
||||
return calendar.getTime();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Date getExpiryDate(PGPSecretKey key) {
|
||||
return getExpiryDate(key.getPublicKey());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isExpired(PGPPublicKey key) {
|
||||
Date creationDate = getCreationDate(key);
|
||||
Date expiryDate = getExpiryDate(key);
|
||||
@ -89,6 +94,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
|
||||
long cnt = 0;
|
||||
if (keyRing == null) {
|
||||
@ -105,6 +111,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
private static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
|
||||
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
|
||||
|
||||
@ -118,6 +125,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
private static Vector<PGPSecretKey> getSigningKeys(PGPSecretKeyRing keyRing) {
|
||||
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
||||
|
||||
@ -131,6 +139,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
private static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
|
||||
Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
|
||||
|
||||
@ -143,26 +152,7 @@ public class PgpKeyHelper {
|
||||
return signingKeys;
|
||||
}
|
||||
|
||||
private static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
|
||||
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;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
|
||||
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
||||
Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
|
||||
@ -181,6 +171,7 @@ public class PgpKeyHelper {
|
||||
return usableKeys;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
|
||||
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
|
||||
Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
|
||||
@ -199,16 +190,6 @@ public class PgpKeyHelper {
|
||||
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) {
|
||||
Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
|
||||
if (signingKeys.size() == 0) {
|
||||
@ -253,6 +234,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static boolean isEncryptionKey(PGPPublicKey key) {
|
||||
if (!key.isEncryptionKey()) {
|
||||
return false;
|
||||
@ -298,6 +280,7 @@ public class PgpKeyHelper {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static boolean isSigningKey(PGPPublicKey key) {
|
||||
if (key.getVersion() <= 3) {
|
||||
return true;
|
||||
@ -328,11 +311,13 @@ public class PgpKeyHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isSigningKey(PGPSecretKey key) {
|
||||
return isSigningKey(key.getPublicKey());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static boolean isCertificationKey(PGPPublicKey key) {
|
||||
if (key.getVersion() <= 3) {
|
||||
return true;
|
||||
@ -358,11 +343,13 @@ public class PgpKeyHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isAuthenticationKey(PGPSecretKey key) {
|
||||
return isAuthenticationKey(key.getPublicKey());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static boolean isAuthenticationKey(PGPPublicKey key) {
|
||||
if (key.getVersion() <= 3) {
|
||||
return true;
|
||||
@ -388,6 +375,7 @@ public class PgpKeyHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isCertificationKey(PGPSecretKey key) {
|
||||
return isCertificationKey(key.getPublicKey());
|
||||
}
|
||||
|
@ -25,25 +25,14 @@ import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
|
||||
import org.spongycastle.openpgp.PGPException;
|
||||
import org.spongycastle.openpgp.PGPLiteralData;
|
||||
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.PGPSignatureSubpacketGenerator;
|
||||
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.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@ -279,19 +268,15 @@ public class PgpSignEncrypt {
|
||||
}
|
||||
|
||||
/* Get keys for signature generation for later usage */
|
||||
PGPSecretKey signingKey = null;
|
||||
PGPSecretKeyRing signingKeyRing = null;
|
||||
PGPPrivateKey signaturePrivateKey = null;
|
||||
String signingUserId = null;
|
||||
CachedSecretKey signingKey = null;
|
||||
if (enableSignature) {
|
||||
CachedSecretKeyRing signingKeyRing = null;
|
||||
try {
|
||||
signingKeyRing = mProviderHelper.getPGPSecretKeyRing(mSignatureMasterKeyId);
|
||||
signingUserId = (String) mProviderHelper.getUnifiedData(mSignatureMasterKeyId,
|
||||
KeychainContract.KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING);
|
||||
signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId);
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
throw new NoSigningKeyException();
|
||||
}
|
||||
signingKey = PgpKeyHelper.getFirstSigningSubkey(signingKeyRing);
|
||||
signingKey = signingKeyRing.getSigningSubKey();
|
||||
if (signingKey == null) {
|
||||
throw new NoSigningKeyException();
|
||||
}
|
||||
@ -302,10 +287,9 @@ public class PgpSignEncrypt {
|
||||
|
||||
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.toCharArray());
|
||||
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
|
||||
if (signaturePrivateKey == null) {
|
||||
try {
|
||||
signingKey.unlock(mSignaturePassphrase);
|
||||
} catch (PgpGeneralException e) {
|
||||
throw new KeyExtractionException();
|
||||
}
|
||||
}
|
||||
@ -333,13 +317,12 @@ public class PgpSignEncrypt {
|
||||
// Asymmetric encryption
|
||||
for (long id : mEncryptionMasterKeyIds) {
|
||||
try {
|
||||
PGPPublicKeyRing keyRing = mProviderHelper.getPGPPublicKeyRing(id);
|
||||
PGPPublicKey key = PgpKeyHelper.getFirstEncryptSubkey(keyRing);
|
||||
if (key != null) {
|
||||
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
|
||||
new JcePublicKeyKeyEncryptionMethodGenerator(key);
|
||||
cPk.addMethod(pubKeyEncryptionGenerator);
|
||||
}
|
||||
CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing(
|
||||
KeyRings.buildUnifiedKeyRingUri(Long.toString(id)));
|
||||
CachedPublicKey key = keyRing.getFirstEncryptSubkey();
|
||||
cPk.addMethod(key.getPubKeyEncryptionGenerator());
|
||||
} catch (PgpGeneralException e) {
|
||||
Log.e(Constants.TAG, "key not found!", e);
|
||||
} catch (ProviderHelper.NotFoundException e) {
|
||||
Log.e(Constants.TAG, "key not found!", e);
|
||||
}
|
||||
@ -353,29 +336,18 @@ public class PgpSignEncrypt {
|
||||
if (enableSignature) {
|
||||
updateProgress(R.string.progress_preparing_signature, 10, 100);
|
||||
|
||||
// content signer based on signing key algorithm and chosen hash algorithm
|
||||
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
||||
signingKey.getPublicKey().getAlgorithm(), mSignatureHashAlgorithm)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
|
||||
int signatureType;
|
||||
if (mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption) {
|
||||
// for sign-only ascii text
|
||||
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||
} else {
|
||||
signatureType = PGPSignature.BINARY_DOCUMENT;
|
||||
}
|
||||
|
||||
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());
|
||||
try {
|
||||
boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption;
|
||||
if (mSignatureForceV3) {
|
||||
signatureV3Generator = signingKey.getV3SignatureGenerator(
|
||||
mSignatureHashAlgorithm,cleartext);
|
||||
} else {
|
||||
signatureGenerator = signingKey.getSignatureGenerator(
|
||||
mSignatureHashAlgorithm, cleartext);
|
||||
}
|
||||
} catch (PgpGeneralException e) {
|
||||
// TODO throw correct type of exception (which shouldn't be PGPException)
|
||||
throw new KeyExtractionException();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,8 @@ public class KeychainContract {
|
||||
public static final String HAS_ANY_SECRET = "has_any_secret";
|
||||
public static final String HAS_ENCRYPT = "has_encrypt";
|
||||
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()
|
||||
.appendPath(BASE_KEY_RINGS).build();
|
||||
@ -123,6 +125,10 @@ public class KeychainContract {
|
||||
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) {
|
||||
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.USER_ID, UserIds.USER_ID);
|
||||
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_ANY_SECRET,
|
||||
"(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET
|
||||
@ -295,6 +301,22 @@ public class KeychainProvider extends ContentProvider {
|
||||
+ " AND " + Tables.CERTS + "." + Certs.VERIFIED
|
||||
+ " = " + 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");
|
||||
// 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.PGPSecretKeyRing;
|
||||
import org.spongycastle.openpgp.PGPSignature;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||
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.PgpHelper;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
|
||||
@ -167,6 +168,7 @@ public class ProviderHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Map<Long, PGPKeyRing> getPGPKeyRings(Uri queryUri) {
|
||||
Cursor cursor = mContentResolver.query(queryUri,
|
||||
new String[]{KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA},
|
||||
@ -188,6 +190,94 @@ public class ProviderHelper {
|
||||
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 {
|
||||
Map<Long, PGPKeyRing> result = getPGPKeyRings(queryUri);
|
||||
if (result.isEmpty()) {
|
||||
@ -197,6 +287,7 @@ public class ProviderHelper {
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(long keyId)
|
||||
throws NotFoundException {
|
||||
Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
|
||||
@ -204,6 +295,7 @@ public class ProviderHelper {
|
||||
return getPGPPublicKeyRing(masterKeyId);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(long keyId)
|
||||
throws NotFoundException {
|
||||
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
|
||||
*/
|
||||
@Deprecated
|
||||
public PGPPublicKeyRing getPGPPublicKeyRing(long masterKeyId) throws NotFoundException {
|
||||
Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
|
||||
return (PGPPublicKeyRing) getPGPKeyRing(queryUri);
|
||||
@ -222,6 +315,7 @@ public class ProviderHelper {
|
||||
/**
|
||||
* Retrieves the actual PGPSecretKeyRing object from the database blob based on the maserKeyId
|
||||
*/
|
||||
@Deprecated
|
||||
public PGPSecretKeyRing getPGPSecretKeyRing(long masterKeyId) throws NotFoundException {
|
||||
Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
|
||||
return (PGPSecretKeyRing) getPGPKeyRing(queryUri);
|
||||
|
Loading…
Reference in New Issue
Block a user