wrapped-key-ring: move more helper methods into keys

This commit is contained in:
Vincent Breitmoser 2014-05-03 19:04:23 +02:00
parent 1f8210f743
commit 2176e1ef1c
5 changed files with 153 additions and 15 deletions

View File

@ -1,26 +1,128 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPOnePassSignature;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.IterableIterator;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class CachedPublicKey {
// this is the parent key ring
private final CachedPublicKeyRing mRing;
final CachedKeyRing mRing;
private final PGPPublicKey mKey;
CachedPublicKey(CachedPublicKeyRing ring, PGPPublicKey key) {
CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) {
mRing = ring;
mKey = key;
}
public CachedPublicKeyRing getKeyRing() {
public long getKeyId() {
return mKey.getKeyID();
}
public Date getCreationTime() {
return mKey.getCreationTime();
}
public Date getExpiryTime() {
Date creationDate = getCreationTime();
if (mKey.getValidDays() == 0) {
// no expiry
return null;
}
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(creationDate);
calendar.add(Calendar.DATE, mKey.getValidDays());
return calendar.getTime();
}
public boolean isMasterKey() {
return mKey.isMasterKey();
}
public int getAlgorithm() {
return mKey.getAlgorithm();
}
public IterableIterator<String> getUserIds() {
return new IterableIterator<String>(mKey.getUserIDs());
}
private Integer mCacheUsage = null;
@SuppressWarnings("unchecked")
public int getKeyUsage() {
if(mCacheUsage == null) {
mCacheUsage = 0;
if (mKey.getVersion() >= 4) {
for (PGPSignature sig : new IterableIterator<PGPSignature>(mKey.getSignatures())) {
if (mKey.isMasterKey() && sig.getKeyID() != mKey.getKeyID()) {
continue;
}
PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets();
if (hashed != null) {
mCacheUsage |= hashed.getKeyFlags();
}
PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
if (unhashed != null) {
mCacheUsage |= unhashed.getKeyFlags();
}
}
}
}
return mCacheUsage;
}
public boolean canAuthenticate() {
return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0;
}
public boolean canCertify() {
return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0;
}
public boolean canEncrypt() {
if (!mKey.isEncryptionKey()) {
return false;
}
// special cases
if (mKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
return true;
}
if (mKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
return true;
}
return mKey.getVersion() <= 3 ||
(getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0;
}
public boolean canSign() {
// special case
if (mKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
return true;
}
return mKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0;
}
public CachedKeyRing getKeyRing() {
return mRing;
}

View File

@ -1,5 +1,6 @@
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;
@ -26,28 +27,25 @@ import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.util.List;
public class CachedSecretKey {
public class CachedSecretKey extends CachedPublicKey {
// this is the parent key ring
private final CachedSecretKeyRing mRing;
private final PGPSecretKey mKey;
private final PGPSecretKey mSecretKey;
private PGPPrivateKey mPrivateKey = null;
CachedSecretKey(CachedSecretKeyRing ring, PGPSecretKey key) {
mRing = ring;
mKey = key;
super(ring, key.getPublicKey());
mSecretKey = key;
}
public CachedSecretKeyRing getRing() {
return mRing;
return (CachedSecretKeyRing) 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);
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
throw new PgpGeneralException("error extracting key!", e);
}
@ -64,7 +62,7 @@ public class CachedSecretKey {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
mKey.getPublicKey().getAlgorithm(), hashAlgo)
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
int signatureType;
@ -96,7 +94,7 @@ public class CachedSecretKey {
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
mKey.getPublicKey().getAlgorithm(), hashAlgo)
mSecretKey.getPublicKey().getAlgorithm(), hashAlgo)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
int signatureType;
@ -144,7 +142,7 @@ public class CachedSecretKey {
{
// TODO: SHA256 fixed?
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
mKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
mSecretKey.getPublicKey().getAlgorithm(), PGPUtil.SHA256)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);

View File

@ -1,13 +1,19 @@
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.JcePBESecretKeyDecryptorBuilder;
import org.sufficientlysecure.keychain.util.IterableIterator;
import java.util.Iterator;
public class CachedSecretKeyRing extends CachedKeyRing {
private PGPSecretKeyRing mRing;
@ -31,6 +37,35 @@ public class CachedSecretKeyRing extends CachedKeyRing {
return new CachedSecretKey(this, mRing.getSecretKey(id));
}
public IterableIterator<CachedSecretKey> iterator() {
return new IterableIterator<CachedSecretKey>(mRing.getSecretKeys());
}
public boolean hasPassphrase() {
PGPSecretKey secretKey = null;
boolean foundValidKey = false;
for (Iterator keys = mRing.getSecretKeys(); keys.hasNext(); ) {
secretKey = (PGPSecretKey) keys.next();
if (!secretKey.isPrivateKeyEmpty()) {
foundValidKey = true;
break;
}
}
if(!foundValidKey) {
return false;
}
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider("SC").build("".toCharArray());
PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
return testKey == null;
} catch(PGPException e) {
// this means the crc check failed -> passphrase required
return true;
}
}
/** This returns the subkey that should be used for signing.
* At this point, this is simply the first suitable subkey.
*/

View File

@ -143,6 +143,7 @@ public class PgpKeyHelper {
return usableKeys;
}
@Deprecated
public static PGPSecretKey getFirstSigningSubkey(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> signingKeys = getUsableSigningKeys(keyRing);
if (signingKeys.size() == 0) {

View File

@ -197,6 +197,7 @@ public class PassphraseCacheService extends Service {
return cachedPassphrase;
}
@Deprecated
public static boolean hasPassphrase(PGPSecretKeyRing secretKeyRing) {
PGPSecretKey secretKey = null;
boolean foundValidKey = false;
@ -228,6 +229,7 @@ public class PassphraseCacheService extends Service {
* @param secretKeyId
* @return true if it has a passphrase
*/
@Deprecated
public static boolean hasPassphrase(Context context, long secretKeyId) {
// check if the key has no passphrase
try {