wrapped-key-ring: redesign underlying CachedKeyRing

This commit is contained in:
Vincent Breitmoser
2014-05-04 12:55:22 +02:00
parent d0e3af505c
commit 411b4cfeb2
6 changed files with 157 additions and 195 deletions

View File

@@ -3,45 +3,66 @@ package org.sufficientlysecure.keychain.pgp;
public abstract class CachedKeyRing {
private final long mMasterKeyId;
private final boolean mCanCertify;
private final byte[] mFingerprint;
private final String mUserId;
private final boolean mHasAnySecret;
private final boolean mIsRevoked;
private final boolean mCanCertify;
private final long mHasEncryptId;
private final long mHasSignId;
private final int mVerified;
private final boolean mHasSecret;
protected CachedKeyRing(long masterKeyId, boolean canCertify,
byte[] fingerprint, String userId, int verified, boolean hasSecret)
protected CachedKeyRing(long masterKeyId, String userId, boolean hasAnySecret,
boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId,
int verified)
{
mMasterKeyId = masterKeyId;
mCanCertify = canCertify;
mFingerprint = fingerprint;
mUserId = userId;
mHasAnySecret = hasAnySecret;
mIsRevoked = isRevoked;
mCanCertify = canCertify;
mHasEncryptId = hasEncryptId;
mHasSignId = hasSignId;
mVerified = verified;
mHasSecret = hasSecret;
}
public byte[] getFingerprint() {
return mFingerprint;
}
public String getPrimaryUserId() {
return mUserId;
}
public long getMasterKeyId() {
return mMasterKeyId;
}
public int getVerified() {
return mVerified;
public String getPrimaryUserId() {
return mUserId;
}
public boolean hasAnySecret() {
return mHasAnySecret;
}
public boolean isRevoked() {
return mIsRevoked;
}
public boolean canCertify() {
return mCanCertify;
}
public boolean hasSecret() {
return mHasSecret;
public long getEncryptId() {
return mHasEncryptId;
}
public boolean hasEncrypt() {
return mHasEncryptId != 0;
}
public long getSignId() {
return mHasSignId;
}
public boolean hasSign() {
return mHasSignId != 0;
}
public int getVerified() {
return mVerified;
}
}

View File

@@ -23,14 +23,14 @@ 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)
public CachedPublicKeyRing(long masterKeyId, String userId, boolean hasAnySecret,
boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId,
int verified, byte[] blob)
{
super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret);
super(masterKeyId, userId, hasAnySecret, isRevoked, canCertify,
hasEncryptId, hasSignId, verified);
mPubKey = pubkey;
mPubKey = blob;
}
PGPPublicKeyRing getRing() {
@@ -52,46 +52,18 @@ public class CachedPublicKeyRing extends CachedKeyRing {
return new CachedPublicKey(this, getRing().getPublicKey(id));
}
public CachedPublicKey getFirstSignSubkey() throws PgpGeneralException {
// only return master key if no other signing key is available
CachedPublicKey masterKey = null;
for (PGPPublicKey k : new IterableIterator<PGPPublicKey>(getRing().getPublicKeys())) {
CachedPublicKey key = new CachedPublicKey(this, k);
if (key.isRevoked() || key.canSign() || key.isExpired()) {
continue;
}
if (key.isMasterKey()) {
masterKey = key;
} else {
return key;
/** Getter that returns the subkey that should be used for signing. */
CachedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());
if(key != null) {
CachedPublicKey cKey = new CachedPublicKey(this, key);
if(!cKey.canEncrypt()) {
throw new PgpGeneralException("key error");
}
return cKey;
}
if(masterKey == null) {
// TODO proper exception
throw new PgpGeneralException("key not found");
}
return masterKey;
}
public CachedPublicKey getFirstEncryptSubkey() throws PgpGeneralException {
// only return master key if no other encryption key is available
CachedPublicKey masterKey = null;
for (PGPPublicKey k : new IterableIterator<PGPPublicKey>(getRing().getPublicKeys())) {
CachedPublicKey key = new CachedPublicKey(this, k);
if (key.isRevoked() || key.canEncrypt() || key.isExpired()) {
continue;
}
if (key.isMasterKey()) {
masterKey = key;
} else {
return key;
}
}
if(masterKey == null) {
// TODO proper exception
throw new PgpGeneralException("key not found");
}
return masterKey;
// TODO handle with proper exception
throw new PgpGeneralException("no encryption key available");
}
public boolean verifySubkeyBinding(CachedPublicKey cachedSubkey) {
@@ -189,4 +161,24 @@ public class CachedPublicKeyRing extends CachedKeyRing {
return validPrimaryKeyBinding;
}
public IterableIterator<CachedPublicKey> iterator() {
final Iterator<PGPPublicKey> it = getRing().getPublicKeys();
return new IterableIterator<CachedPublicKey>(new Iterator<CachedPublicKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public CachedPublicKey next() {
return new CachedPublicKey(CachedPublicKeyRing.this, it.next());
}
@Override
public void remove() {
it.remove();
}
});
}
}

View File

@@ -1,18 +1,15 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPPrivateKey;
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.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.util.IterableIterator;
import java.io.IOException;
@@ -23,12 +20,13 @@ 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)
public CachedSecretKeyRing(long masterKeyId, String userId, boolean hasAnySecret,
boolean isRevoked, boolean canCertify, long hasEncryptId, long hasSignId,
int verified, byte[] blob)
{
super(masterKeyId, canCertify, fingerprint, userId, verified, hasSecret);
super(masterKeyId, userId, hasAnySecret,
isRevoked, canCertify, hasEncryptId, hasSignId,
verified);
mRing = (PGPSecretKeyRing) PgpConversionHelper.BytesToPGPKeyRing(blob);
}
@@ -45,8 +43,18 @@ public class CachedSecretKeyRing extends CachedKeyRing {
return new CachedSecretKey(this, mRing.getSecretKey(id));
}
public IterableIterator<CachedSecretKey> iterator() {
return new IterableIterator<CachedSecretKey>(mRing.getSecretKeys());
/** Getter that returns the subkey that should be used for signing. */
CachedSecretKey getSigningSubKey() throws PgpGeneralException {
PGPSecretKey key = mRing.getSecretKey(getSignId());
if(key != null) {
CachedSecretKey cKey = new CachedSecretKey(this, key);
if(!cKey.canSign()) {
throw new PgpGeneralException("key error");
}
return cKey;
}
// TODO handle with proper exception
throw new PgpGeneralException("no signing key available");
}
public boolean hasPassphrase() {
@@ -74,50 +82,6 @@ public class CachedSecretKeyRing extends CachedKeyRing {
}
}
/** 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;
}
public UncachedSecretKeyRing changeSecretKeyPassphrase(String oldPassphrase,
String newPassphrase)
throws IOException, PGPException, NoSuchProviderException {
@@ -141,4 +105,24 @@ public class CachedSecretKeyRing extends CachedKeyRing {
}
public IterableIterator<CachedSecretKey> iterator() {
final Iterator<PGPSecretKey> it = mRing.getSecretKeys();
return new IterableIterator<CachedSecretKey>(new Iterator<CachedSecretKey>() {
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public CachedSecretKey next() {
return new CachedSecretKey(CachedSecretKeyRing.this, it.next());
}
@Override
public void remove() {
it.remove();
}
});
}
}

View File

@@ -270,14 +270,15 @@ public class PgpSignEncrypt {
/* Get keys for signature generation for later usage */
CachedSecretKey signingKey = null;
if (enableSignature) {
CachedSecretKeyRing signingKeyRing = null;
CachedSecretKeyRing signingKeyRing;
try {
signingKeyRing = mProviderHelper.getCachedSecretKeyRing(mSignatureMasterKeyId);
} catch (ProviderHelper.NotFoundException e) {
throw new NoSigningKeyException();
}
signingKey = signingKeyRing.getSigningSubKey();
if (signingKey == null) {
try {
signingKey = signingKeyRing.getSigningSubKey();
} catch(PgpGeneralException e) {
throw new NoSigningKeyException();
}
@@ -319,7 +320,7 @@ public class PgpSignEncrypt {
try {
CachedPublicKeyRing keyRing = mProviderHelper.getCachedPublicKeyRing(
KeyRings.buildUnifiedKeyRingUri(Long.toString(id)));
CachedPublicKey key = keyRing.getFirstEncryptSubkey();
CachedPublicKey key = keyRing.getEncryptionSubKey();
cPk.addMethod(key.getPubKeyEncryptionGenerator());
} catch (PgpGeneralException e) {
Log.e(Constants.TAG, "key not found!", e);