aboutsummaryrefslogtreecommitdiffstats
path: root/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper
diff options
context:
space:
mode:
Diffstat (limited to 'OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper')
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpHelper.java118
-rw-r--r--OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java49
2 files changed, 154 insertions, 13 deletions
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpHelper.java
index f59bd58de..810f3a6f2 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpHelper.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpHelper.java
@@ -24,12 +24,16 @@ import java.util.Locale;
import java.util.Vector;
import org.spongycastle.bcpg.sig.KeyFlags;
+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.PGPSignatureSubpacketVector;
+import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+import org.spongycastle.openpgp.PGPException;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.IterableIterator;
@@ -77,6 +81,22 @@ public class PgpHelper {
}
@SuppressWarnings("unchecked")
+ public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) {
+ long cnt = 0;
+ if (keyRing == null) {
+ return null;
+ }
+ for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
+ if (cnt == num) {
+ return key;
+ }
+ cnt++;
+ }
+
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
public static Vector<PGPPublicKey> getEncryptKeys(PGPPublicKeyRing keyRing) {
Vector<PGPPublicKey> encryptKeys = new Vector<PGPPublicKey>();
@@ -102,6 +122,19 @@ public class PgpHelper {
return signingKeys;
}
+ @SuppressWarnings("unchecked")
+ public static Vector<PGPSecretKey> getCertificationKeys(PGPSecretKeyRing keyRing) {
+ Vector<PGPSecretKey> signingKeys = new Vector<PGPSecretKey>();
+
+ for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
+ if (isCertificationKey(key)) {
+ signingKeys.add(key);
+ }
+ }
+
+ return signingKeys;
+ }
+
public static Vector<PGPPublicKey> getUsableEncryptKeys(PGPPublicKeyRing keyRing) {
Vector<PGPPublicKey> usableKeys = new Vector<PGPPublicKey>();
Vector<PGPPublicKey> encryptKeys = getEncryptKeys(keyRing);
@@ -137,6 +170,24 @@ public class PgpHelper {
return isExpired(key.getPublicKey());
}
+ public static Vector<PGPSecretKey> getUsableCertificationKeys(PGPSecretKeyRing keyRing) {
+ Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
+ Vector<PGPSecretKey> signingKeys = getCertificationKeys(keyRing);
+ PGPSecretKey masterKey = null;
+ for (int i = 0; i < signingKeys.size(); ++i) {
+ PGPSecretKey key = signingKeys.get(i);
+ if (key.isMasterKey()) {
+ masterKey = key;
+ } else {
+ usableKeys.add(key);
+ }
+ }
+ if (masterKey != null) {
+ usableKeys.add(masterKey);
+ }
+ return usableKeys;
+ }
+
public static Vector<PGPSecretKey> getUsableSigningKeys(PGPSecretKeyRing keyRing) {
Vector<PGPSecretKey> usableKeys = new Vector<PGPSecretKey>();
Vector<PGPSecretKey> signingKeys = getSigningKeys(keyRing);
@@ -188,6 +239,19 @@ public class PgpHelper {
return encryptKeys.get(0);
}
+ public static PGPSecretKey getCertificationKey(Context context, long masterKeyId) {
+ PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context,
+ masterKeyId);
+ if (keyRing == null) {
+ return null;
+ }
+ Vector<PGPSecretKey> signingKeys = getUsableCertificationKeys(keyRing);
+ if (signingKeys.size() == 0) {
+ return null;
+ }
+ return signingKeys.get(0);
+ }
+
public static PGPSecretKey getSigningKey(Context context, long masterKeyId) {
PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingByMasterKeyId(context,
masterKeyId);
@@ -313,6 +377,36 @@ public class PgpHelper {
return isSigningKey(key.getPublicKey());
}
+ @SuppressWarnings("unchecked")
+ public static boolean isCertificationKey(PGPPublicKey key) {
+ if (key.getVersion() <= 3) {
+ 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.CERTIFY_OTHER) != 0) {
+ return true;
+ }
+
+ PGPSignatureSubpacketVector unhashed = sig.getUnhashedSubPackets();
+
+ if (unhashed != null && (unhashed.getKeyFlags() & KeyFlags.CERTIFY_OTHER) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean isCertificationKey(PGPSecretKey key) {
+ return isCertificationKey(key.getPublicKey());
+ }
+
public static String getAlgorithmInfo(PGPPublicKey key) {
return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
}
@@ -385,6 +479,30 @@ public class PgpHelper {
return convertFingerprintToHex(key.getFingerprint());
}
+ public static boolean isSecretKeyPrivateEmpty(PGPSecretKey secretKey) {
+ try {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(PgpMain.BOUNCY_CASTLE_PROVIDER_NAME).build(new char[] {});
+ PGPPrivateKey testKey = secretKey.extractPrivateKey(
+ keyDecryptor);
+ if (testKey != null) {
+ return false;
+ }
+ } catch (PGPException e) { //exception if wrong key => not empty
+ return false; //all good if this fails, we likely didn't use the right password
+ }
+ return true;
+ }
+
+ public static boolean isSecretKeyPrivateEmpty(Context context, long keyId) {
+ PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, keyId);
+ if (secretKey == null) {
+ Log.e(Constants.TAG, "Key could not be found!");
+ return false; //could be a public key, assume it is not empty
+ }
+ return isSecretKeyPrivateEmpty(secretKey);
+ }
+
public static String getSmallFingerPrint(long keyId) {
String fingerPrint = Long.toHexString(keyId & 0xffffffffL).toUpperCase(Locale.US);
while (fingerPrint.length() < 8) {
diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java
index 26842e4dc..142dfec01 100644
--- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java
+++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/helper/PgpMain.java
@@ -84,6 +84,7 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream;
import org.sufficientlysecure.keychain.util.Primes;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import org.sufficientlysecure.keychain.util.KeyServer.AddKeyException;
+import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.R;
import android.content.Context;
@@ -308,6 +309,31 @@ public class PgpMain {
return secKeyRing;
}
+ public static void changeSecretKeyPassphrase(Context context,
+ PGPSecretKeyRing keyRing, String oldPassPhrase, String newPassPhrase,
+ ProgressDialogUpdater progress) throws IOException, PGPException, PGPException,
+ NoSuchProviderException {
+
+ updateProgress(progress, R.string.progress_buildingKey, 0, 100);
+ if (oldPassPhrase == null) {
+ oldPassPhrase = "";
+ }
+ if (newPassPhrase == null) {
+ newPassPhrase = "";
+ }
+
+ PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(keyRing,
+ oldPassPhrase.toCharArray(), newPassPhrase.toCharArray(), keyRing.getSecretKey().getKeyEncryptionAlgorithm(),
+ new SecureRandom(), BOUNCY_CASTLE_PROVIDER_NAME);
+
+ updateProgress(progress, R.string.progress_savingKeyRing, 50, 100);
+
+ ProviderHelper.saveKeyRing(context, newKeyRing);
+
+ updateProgress(progress, R.string.progress_done, 100, 100);
+
+ }
+
public static void buildSecretKey(Context context, ArrayList<String> userIds,
ArrayList<PGPSecretKey> keys, ArrayList<Integer> keysUsages, long masterKeyId,
String oldPassPhrase, String newPassPhrase, ProgressDialogUpdater progress)
@@ -483,25 +509,22 @@ public class PgpMain {
* @param keyring
* @return
*/
+ @SuppressWarnings("unchecked")
public static int storeKeyRingInCache(Context context, PGPKeyRing keyring) {
int status = Integer.MIN_VALUE; // out of bounds value (Id.return_value.*)
try {
if (keyring instanceof PGPSecretKeyRing) {
PGPSecretKeyRing secretKeyRing = (PGPSecretKeyRing) keyring;
boolean save = true;
- try {
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(BOUNCY_CASTLE_PROVIDER_NAME).build(new char[] {});
- PGPPrivateKey testKey = secretKeyRing.getSecretKey().extractPrivateKey(
- keyDecryptor);
- if (testKey == null) {
- // this is bad, something is very wrong... likely a --export-secret-subkeys
- // export
- save = false;
- status = Id.return_value.bad;
+
+ for (PGPSecretKey testSecretKey : new IterableIterator<PGPSecretKey>(secretKeyRing.getSecretKeys())) {
+ if (!testSecretKey.isMasterKey()) {
+ if (PgpHelper.isSecretKeyPrivateEmpty(testSecretKey)) {
+ // this is bad, something is very wrong...
+ save = false;
+ status = Id.return_value.bad;
+ }
}
- } catch (PGPException e) {
- // all good if this fails, we likely didn't use the right password
}
if (save) {
@@ -1109,7 +1132,7 @@ public class PgpMain {
} else {
PGPPublicKeyRing pubring = ProviderHelper.getPGPPublicKeyRingByKeyId(context, pubKeyId);
- PGPSecretKey signingKey = PgpHelper.getSigningKey(context, masterKeyId);
+ PGPSecretKey signingKey = PgpHelper.getCertificationKey(context, masterKeyId);
if (signingKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_signatureFailed));
}