mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-24 01:32:16 -05:00
wrapped-key-ring: introduce Uncached*Key objects
This commit is contained in:
parent
411b4cfeb2
commit
8cf0638f54
@ -1,139 +1,28 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
|
||||||
import org.spongycastle.openpgp.PGPException;
|
import org.spongycastle.openpgp.PGPException;
|
||||||
import org.spongycastle.openpgp.PGPOnePassSignature;
|
import org.spongycastle.openpgp.PGPOnePassSignature;
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
|
||||||
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
|
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
|
|
||||||
public class CachedPublicKey {
|
public class CachedPublicKey extends UncachedPublicKey {
|
||||||
|
|
||||||
// this is the parent key ring
|
// this is the parent key ring
|
||||||
final CachedKeyRing mRing;
|
final CachedKeyRing mRing;
|
||||||
|
|
||||||
private final PGPPublicKey mKey;
|
|
||||||
|
|
||||||
CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) {
|
CachedPublicKey(CachedKeyRing ring, PGPPublicKey key) {
|
||||||
|
super(key);
|
||||||
mRing = ring;
|
mRing = ring;
|
||||||
mKey = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getKeyId() {
|
|
||||||
return mKey.getKeyID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRevoked() {
|
|
||||||
return mKey.isRevoked();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 isExpired() {
|
|
||||||
Date creationDate = mKey.getCreationTime();
|
|
||||||
Date expiryDate = mKey.getValidSeconds() > 0
|
|
||||||
? new Date(creationDate.getTime() + mKey.getValidSeconds() * 1000) : null;
|
|
||||||
|
|
||||||
Date now = new Date();
|
|
||||||
return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMasterKey() {
|
|
||||||
return mKey.isMasterKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAlgorithm() {
|
|
||||||
return mKey.getAlgorithm();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IterableIterator<String> getUserIds() {
|
public IterableIterator<String> getUserIds() {
|
||||||
return new IterableIterator<String>(mKey.getUserIDs());
|
return new IterableIterator<String>(mPublicKey.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() {
|
public CachedKeyRing getKeyRing() {
|
||||||
@ -141,21 +30,21 @@ public class CachedPublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() {
|
JcePublicKeyKeyEncryptionMethodGenerator getPubKeyEncryptionGenerator() {
|
||||||
return new JcePublicKeyKeyEncryptionMethodGenerator(mKey);
|
return new JcePublicKeyKeyEncryptionMethodGenerator(mPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initSignature(PGPSignature sig) throws PGPException {
|
public void initSignature(PGPSignature sig) throws PGPException {
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
sig.init(contentVerifierBuilderProvider, mKey);
|
sig.init(contentVerifierBuilderProvider, mPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initSignature(PGPOnePassSignature sig) throws PGPException {
|
public void initSignature(PGPOnePassSignature sig) throws PGPException {
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider =
|
||||||
new JcaPGPContentVerifierBuilderProvider()
|
new JcaPGPContentVerifierBuilderProvider()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
sig.init(contentVerifierBuilderProvider, mKey);
|
sig.init(contentVerifierBuilderProvider, mPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Verify a signature for this pubkey, after it has been initialized by the signer using
|
/** Verify a signature for this pubkey, after it has been initialized by the signer using
|
||||||
@ -164,18 +53,10 @@ public class CachedPublicKey {
|
|||||||
*/
|
*/
|
||||||
public boolean verifySignature(PGPSignature sig, String uid) throws PGPException {
|
public boolean verifySignature(PGPSignature sig, String uid) throws PGPException {
|
||||||
try {
|
try {
|
||||||
return sig.verifyCertification(uid, mKey);
|
return sig.verifyCertification(uid, mPublicKey);
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
throw new PGPException("Error!", e);
|
throw new PGPException("Error!", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getFingerprint() {
|
|
||||||
return mKey.getFingerprint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that this method has package visibility - no access outside the pgp package!
|
|
||||||
PGPPublicKey getKey() {
|
|
||||||
return mKey;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class CachedPublicKeyRing extends CachedKeyRing {
|
|||||||
boolean validPrimaryKeyBinding = false;
|
boolean validPrimaryKeyBinding = false;
|
||||||
|
|
||||||
PGPPublicKey masterKey = getRing().getPublicKey();
|
PGPPublicKey masterKey = getRing().getPublicKey();
|
||||||
PGPPublicKey subKey = cachedSubkey.getKey();
|
PGPPublicKey subKey = cachedSubkey.getPublicKey();
|
||||||
|
|
||||||
// Is this the master key? Match automatically, then.
|
// Is this the master key? Match automatically, then.
|
||||||
if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) {
|
if(Arrays.equals(masterKey.getFingerprint(), subKey.getFingerprint())) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
|
||||||
import org.spongycastle.openpgp.PGPException;
|
import org.spongycastle.openpgp.PGPException;
|
||||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
@ -157,7 +156,7 @@ public class CachedSecretKey extends CachedPublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the master subkey (which we certify for)
|
// get the master subkey (which we certify for)
|
||||||
PGPPublicKey publicKey = publicKeyRing.getSubkey().getKey();
|
PGPPublicKey publicKey = publicKeyRing.getSubkey().getPublicKey();
|
||||||
|
|
||||||
// fetch public key ring, add the certification and return it
|
// fetch public key ring, add the certification and return it
|
||||||
for (String userId : new IterableIterator<String>(userIds.iterator())) {
|
for (String userId : new IterableIterator<String>(userIds.iterator())) {
|
||||||
@ -175,4 +174,8 @@ public class CachedSecretKey extends CachedPublicKey {
|
|||||||
// the private key is called without a previous call to unlock()
|
// the private key is called without a previous call to unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UncachedSecretKey getUncached() {
|
||||||
|
return new UncachedSecretKey(mSecretKey);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
|
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
|
||||||
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
public class UncachedPublicKey {
|
||||||
|
protected final PGPPublicKey mPublicKey;
|
||||||
|
private Integer mCacheUsage = null;
|
||||||
|
|
||||||
|
public UncachedPublicKey(PGPPublicKey key) {
|
||||||
|
mPublicKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getKeyId() {
|
||||||
|
return mPublicKey.getKeyID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRevoked() {
|
||||||
|
return mPublicKey.isRevoked();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreationTime() {
|
||||||
|
return mPublicKey.getCreationTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getExpiryTime() {
|
||||||
|
Date creationDate = getCreationTime();
|
||||||
|
if (mPublicKey.getValidDays() == 0) {
|
||||||
|
// no expiry
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Calendar calendar = GregorianCalendar.getInstance();
|
||||||
|
calendar.setTime(creationDate);
|
||||||
|
calendar.add(Calendar.DATE, mPublicKey.getValidDays());
|
||||||
|
|
||||||
|
return calendar.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired() {
|
||||||
|
Date creationDate = mPublicKey.getCreationTime();
|
||||||
|
Date expiryDate = mPublicKey.getValidSeconds() > 0
|
||||||
|
? new Date(creationDate.getTime() + mPublicKey.getValidSeconds() * 1000) : null;
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
return creationDate.after(now) || (expiryDate != null && expiryDate.before(now));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMasterKey() {
|
||||||
|
return mPublicKey.isMasterKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAlgorithm() {
|
||||||
|
return mPublicKey.getAlgorithm();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isElGamalEncrypt() {
|
||||||
|
return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDSA() {
|
||||||
|
return getAlgorithm() == PGPPublicKey.DSA;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int getKeyUsage() {
|
||||||
|
if(mCacheUsage == null) {
|
||||||
|
mCacheUsage = 0;
|
||||||
|
if (mPublicKey.getVersion() >= 4) {
|
||||||
|
for (PGPSignature sig : new IterableIterator<PGPSignature>(mPublicKey.getSignatures())) {
|
||||||
|
if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.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 mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canCertify() {
|
||||||
|
return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canEncrypt() {
|
||||||
|
if (!mPublicKey.isEncryptionKey()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// special cases
|
||||||
|
if (mPublicKey.getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_ENCRYPT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mPublicKey.getVersion() <= 3 ||
|
||||||
|
(getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canSign() {
|
||||||
|
// special case
|
||||||
|
if (mPublicKey.getAlgorithm() == PGPPublicKey.RSA_SIGN) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mPublicKey.getVersion() <= 3 || (getKeyUsage() & KeyFlags.SIGN_DATA) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getFingerprint() {
|
||||||
|
return mPublicKey.getFingerprint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this method has package visibility - no access outside the pgp package!
|
||||||
|
PGPPublicKey getPublicKey() {
|
||||||
|
return mPublicKey;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
import org.spongycastle.openpgp.PGPSecretKey;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public class UncachedSecretKey extends UncachedPublicKey {
|
||||||
|
|
||||||
|
final PGPSecretKey mSecretKey;
|
||||||
|
|
||||||
|
public UncachedSecretKey(PGPSecretKey secretKey) {
|
||||||
|
super(secretKey.getPublicKey());
|
||||||
|
mSecretKey = secretKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public PGPSecretKey getSecretKeyExternal() {
|
||||||
|
return mSecretKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encodeSecretKey(OutputStream os) throws IOException {
|
||||||
|
mSecretKey.encode(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user