Merge branch 'master' into yubikey

Conflicts:
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/Preferences.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
	OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
This commit is contained in:
Dominik Schürmann
2014-08-28 11:00:18 +02:00
171 changed files with 9435 additions and 2107 deletions

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,10 +61,6 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {
return mRing;
}
public void encode(ArmoredOutputStream stream) throws IOException {
getRing().encode(stream);
}
/** Getter that returns the subkey that should be used for signing. */
CanonicalizedPublicKey getEncryptionSubKey() throws PgpGeneralException {
PGPPublicKey key = getRing().getPublicKey(getEncryptId());

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -523,13 +523,7 @@ public class PgpDecryptVerify {
// update signature buffer if signature is also present
if (signature != null) {
try {
signature.update(buffer, 0, length);
} catch (SignatureException e) {
Log.e(Constants.TAG, "SignatureException -> Not a valid signature!", e);
signatureResultBuilder.validSignature(false);
signature = null;
}
signature.update(buffer, 0, length);
}
alreadyWritten += length;

View File

@@ -29,7 +29,6 @@ import org.sufficientlysecure.keychain.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
import java.util.regex.Pattern;
@@ -68,76 +67,6 @@ public class PgpHelper {
}
}
// public static final class content {
// public static final int unknown = 0;
// public static final int encrypted_data = 1;
// public static final int keys = 2;
// }
//
// public static int getStreamContent(Context context, InputStream inStream) throws IOException {
//
// InputStream in = PGPUtil.getDecoderStream(inStream);
// PGPObjectFactory pgpF = new PGPObjectFactory(in);
// Object object = pgpF.nextObject();
// while (object != null) {
// if (object instanceof PGPPublicKeyRing || object instanceof PGPSecretKeyRing) {
// return Id.content.keys;
// } else if (object instanceof PGPEncryptedDataList) {
// return Id.content.encrypted_data;
// }
// object = pgpF.nextObject();
// }
//
// return Id.content.unknown;
// }
/**
* Generate a random filename
*
* @param length
* @return
*/
public static String generateRandomFilename(int length) {
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[length];
random.nextBytes(bytes);
String result = "";
for (int i = 0; i < length; ++i) {
int v = (bytes[i] + 256) % 64;
if (v < 10) {
result += (char) ('0' + v);
} else if (v < 36) {
result += (char) ('A' + v - 10);
} else if (v < 62) {
result += (char) ('a' + v - 36);
} else if (v == 62) {
result += '_';
} else if (v == 63) {
result += '.';
}
}
return result;
}
/**
* Go once through stream to get length of stream. The length is later used to display progress
* when encrypting/decrypting
*
* @param in
* @return
* @throws IOException
*/
public static long getLengthOfStream(InputStream in) throws IOException {
long size = 0;
long n = 0;
byte dummy[] = new byte[0x10000];
while ((n = in.read(dummy)) > 0) {
size += n;
}
return size;
}
/**
* Deletes file securely by overwriting it with random data before deleting it.
* <p/>

View File

@@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult;
import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -43,6 +44,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PgpImportExport {
@@ -60,10 +62,14 @@ public class PgpImportExport {
private ProviderHelper mProviderHelper;
public PgpImportExport(Context context, Progressable progressable) {
this(context, new ProviderHelper(context), progressable);
}
public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable) {
super();
this.mContext = context;
this.mProgressable = progressable;
this.mProviderHelper = new ProviderHelper(context);
this.mProviderHelper = providerHelper;
}
public PgpImportExport(Context context,
@@ -93,7 +99,7 @@ public class PgpImportExport {
}
}
public boolean uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) {
public void uploadKeyRingToServer(HkpKeyserver server, CanonicalizedPublicKeyRing keyring) throws AddKeyException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
@@ -103,13 +109,9 @@ public class PgpImportExport {
String armoredKey = bos.toString("UTF-8");
server.add(armoredKey);
return true;
} catch (IOException e) {
return false;
} catch (AddKeyException e) {
// TODO: tell the user?
return false;
Log.e(Constants.TAG, "IOException", e);
throw new AddKeyException();
} finally {
try {
if (aos != null) {
@@ -124,20 +126,23 @@ public class PgpImportExport {
/** Imports keys from given data. If keyIds is given only those are imported */
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
return importKeyRings(entries.iterator(), entries.size());
}
public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
if (entries == null || entries.size() == 0) {
if (entries == null || !entries.hasNext()) {
return new ImportKeyResult(
ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0);
ImportKeyResult.RESULT_FAIL_NOTHING, mProviderHelper.getLog(), 0, 0, 0, 0);
}
int newKeys = 0, oldKeys = 0, badKeys = 0;
int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0;
int position = 0;
int progSteps = 100 / entries.size();
for (ParcelableKeyRing entry : entries) {
double progSteps = 100.0 / num;
for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) {
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -157,10 +162,10 @@ public class PgpImportExport {
SaveKeyringResult result;
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key,
new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
new ProgressScaler(mProgressable, position, (position+1)*progSteps, 100));
new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
}
if (!result.success()) {
badKeys += 1;
@@ -168,6 +173,9 @@ public class PgpImportExport {
oldKeys += 1;
} else {
newKeys += 1;
if (key.isSecret()) {
secret += 1;
}
}
} catch (IOException e) {
@@ -204,7 +212,7 @@ public class PgpImportExport {
}
}
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys);
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);
}

View File

@@ -24,10 +24,16 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ForegroundColorSpan;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.nist.NISTNamedCurves;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
import org.spongycastle.util.encoders.Hex;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
import org.sufficientlysecure.keychain.util.Log;
import java.security.DigestException;
@@ -37,18 +43,14 @@ import java.util.Locale;
public class PgpKeyHelper {
public static String getAlgorithmInfo(int algorithm) {
return getAlgorithmInfo(null, algorithm, 0);
}
public static String getAlgorithmInfo(Context context, int algorithm) {
return getAlgorithmInfo(context, algorithm, 0);
public static String getAlgorithmInfo(int algorithm, Integer keySize, String oid) {
return getAlgorithmInfo(null, algorithm, keySize, oid);
}
/**
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
*/
public static String getAlgorithmInfo(Context context, int algorithm, int keySize) {
public static String getAlgorithmInfo(Context context, int algorithm, Integer keySize, String oid) {
String algorithmStr;
switch (algorithm) {
@@ -69,10 +71,19 @@ public class PgpKeyHelper {
break;
}
case PublicKeyAlgorithmTags.ECDSA:
case PublicKeyAlgorithmTags.ECDSA: {
if (oid == null) {
return "ECDSA";
}
String oidName = PgpKeyHelper.getCurveInfo(context, oid);
return "ECDSA (" + oidName + ")";
}
case PublicKeyAlgorithmTags.ECDH: {
algorithmStr = "ECC";
break;
if (oid == null) {
return "ECDH";
}
String oidName = PgpKeyHelper.getCurveInfo(context, oid);
return "ECDH (" + oidName + ")";
}
default: {
@@ -90,6 +101,106 @@ public class PgpKeyHelper {
return algorithmStr;
}
public static String getAlgorithmInfo(Algorithm algorithm, Integer keySize, Curve curve) {
return getAlgorithmInfo(null, algorithm, keySize, curve);
}
/**
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
*/
public static String getAlgorithmInfo(Context context, Algorithm algorithm, Integer keySize, Curve curve) {
String algorithmStr;
switch (algorithm) {
case RSA: {
algorithmStr = "RSA";
break;
}
case DSA: {
algorithmStr = "DSA";
break;
}
case ELGAMAL: {
algorithmStr = "ElGamal";
break;
}
case ECDSA: {
algorithmStr = "ECDSA";
if (curve != null) {
algorithmStr += " (" + getCurveInfo(context, curve) + ")";
}
return algorithmStr;
}
case ECDH: {
algorithmStr = "ECDH";
if (curve != null) {
algorithmStr += " (" + getCurveInfo(context, curve) + ")";
}
return algorithmStr;
}
default: {
if (context != null) {
algorithmStr = context.getResources().getString(R.string.unknown_algorithm);
} else {
algorithmStr = "unknown";
}
break;
}
}
if (keySize != null && keySize > 0)
return algorithmStr + ", " + keySize + " bit";
else
return algorithmStr;
}
// Return name of a curve. These are names, no need for translation
public static String getCurveInfo(Context context, Curve curve) {
switch(curve) {
case NIST_P256:
return "NIST P-256";
case NIST_P384:
return "NIST P-384";
case NIST_P521:
return "NIST P-521";
/* see SaveKeyringParcel
case BRAINPOOL_P256:
return "Brainpool P-256";
case BRAINPOOL_P384:
return "Brainpool P-384";
case BRAINPOOL_P512:
return "Brainpool P-512";
*/
}
if (context != null) {
return context.getResources().getString(R.string.unknown_algorithm);
} else {
return "unknown";
}
}
public static String getCurveInfo(Context context, String oidStr) {
ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(oidStr);
String name;
name = NISTNamedCurves.getName(oid);
if (name != null) {
return name;
}
name = TeleTrusTNamedCurves.getName(oid);
if (name != null) {
return name;
}
if (context != null) {
return context.getResources().getString(R.string.unknown_algorithm);
} else {
return "unknown";
}
}
/**
* Converts fingerprint to hex
* <p/>

View File

@@ -70,7 +70,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId;
private int mSignatureHashAlgorithm;
private String mSignaturePassphrase;
private boolean mEncryptToSigner;
private long mAdditionalEncryptId;
private boolean mCleartextInput;
private String mOriginalFilename;
@@ -103,7 +103,7 @@ public class PgpSignEncrypt {
this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId;
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
this.mEncryptToSigner = builder.mEncryptToSigner;
this.mAdditionalEncryptId = builder.mAdditionalEncryptId;
this.mCleartextInput = builder.mCleartextInput;
this.mNfcSignedHash = builder.mNfcSignedHash;
this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp;
@@ -127,7 +127,7 @@ public class PgpSignEncrypt {
private long mSignatureMasterKeyId = Constants.key.none;
private int mSignatureHashAlgorithm = 0;
private String mSignaturePassphrase = null;
private boolean mEncryptToSigner = false;
private long mAdditionalEncryptId = Constants.key.none;
private boolean mCleartextInput = false;
private String mOriginalFilename = "";
private byte[] mNfcSignedHash = null;
@@ -175,7 +175,7 @@ public class PgpSignEncrypt {
}
public Builder setSignatureMasterKeyId(long signatureMasterKeyId) {
this.mSignatureMasterKeyId = signatureMasterKeyId;
mSignatureMasterKeyId = signatureMasterKeyId;
return this;
}
@@ -192,11 +192,11 @@ public class PgpSignEncrypt {
/**
* Also encrypt with the signing keyring
*
* @param encryptToSigner
* @param additionalEncryptId
* @return
*/
public Builder setEncryptToSigner(boolean encryptToSigner) {
mEncryptToSigner = encryptToSigner;
public Builder setAdditionalEncryptId(long additionalEncryptId) {
mAdditionalEncryptId = additionalEncryptId;
return this;
}
@@ -288,10 +288,10 @@ public class PgpSignEncrypt {
+ "\nenableCompression:" + enableCompression
+ "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput);
// add signature key id to encryption ids (self-encrypt)
if (enableEncryption && enableSignature && mEncryptToSigner) {
// add additional key id to encryption ids (mostly to do self-encryption)
if (enableEncryption && mAdditionalEncryptId != Constants.key.none) {
mEncryptionMasterKeyIds = Arrays.copyOf(mEncryptionMasterKeyIds, mEncryptionMasterKeyIds.length + 1);
mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId;
mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mAdditionalEncryptId;
}
ArmoredOutputStream armorOut = null;

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +45,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
@@ -55,7 +58,8 @@ import java.util.TreeSet;
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
* used to move around pgp key rings in non crypto related (UI, mostly) code.
* It should be used for simple inspection only until it saved in the database,
* all actual crypto operations should work with WrappedKeyRings exclusively.
* all actual crypto operations should work with CanonicalizedKeyRings
* exclusively.
*
* This class is also special in that it can hold either the PGPPublicKeyRing
* or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are
@@ -118,6 +122,10 @@ public class UncachedKeyRing {
return mRing.getPublicKey().getFingerprint();
}
public int getVersion() {
return mRing.getPublicKey().getVersion();
}
public static UncachedKeyRing decodeFromData(byte[] data)
throws PgpGeneralException, IOException {
@@ -211,8 +219,7 @@ public class UncachedKeyRing {
aos.close();
}
/** "Canonicalizes" a public key, removing inconsistencies in the process. This variant can be
* applied to public keyrings only.
/** "Canonicalizes" a public key, removing inconsistencies in the process.
*
* More specifically:
* - Remove all non-verifying self-certificates
@@ -229,9 +236,9 @@ public class UncachedKeyRing {
* - If the key is a secret key, remove all certificates by foreign keys
* - If no valid user id remains, log an error and return null
*
* This operation writes an OperationLog which can be used as part of a OperationResultParcel.
* This operation writes an OperationLog which can be used as part of an OperationResultParcel.
*
* @return A canonicalized key, or null on fatal error
* @return A canonicalized key, or null on fatal error (log will include a message in this case)
*
*/
@SuppressWarnings("ConstantConditions")
@@ -241,6 +248,12 @@ public class UncachedKeyRing {
indent, PgpKeyHelper.convertKeyIdToHex(getMasterKeyId()));
indent += 1;
// do not accept v3 keys
if (getVersion() <= 3) {
log.add(LogLevel.ERROR, LogType.MSG_KC_V3_KEY, indent);
return null;
}
final Date now = new Date();
int redundantCerts = 0, badCerts = 0;
@@ -259,13 +272,12 @@ public class UncachedKeyRing {
for (PGPSignature zert : new IterableIterator<PGPSignature>(masterKey.getKeySignatures())) {
int type = zert.getSignatureType();
// Disregard certifications on user ids, we will deal with those later
// These should most definitely not be here...
if (type == PGPSignature.NO_CERTIFICATION
|| type == PGPSignature.DEFAULT_CERTIFICATION
|| type == PGPSignature.CASUAL_CERTIFICATION
|| type == PGPSignature.POSITIVE_CERTIFICATION
|| type == PGPSignature.CERTIFICATION_REVOCATION) {
// These should not be here...
log.add(LogLevel.WARN, LogType.MSG_KC_REVOKE_BAD_TYPE_UID, indent);
modified = PGPPublicKey.removeCertification(modified, zert);
badCerts += 1;
@@ -328,7 +340,17 @@ public class UncachedKeyRing {
}
}
ArrayList<String> processedUserIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
// check for duplicate user ids
if (processedUserIds.contains(userId)) {
log.add(LogLevel.WARN, LogType.MSG_KC_UID_DUP,
indent, userId);
// strip out the first found user id with this name
modified = PGPPublicKey.removeCertification(modified, userId);
}
processedUserIds.add(userId);
PGPSignature selfCert = null;
revocation = null;
@@ -405,13 +427,13 @@ public class UncachedKeyRing {
if (selfCert == null) {
selfCert = zert;
} else if (selfCert.getCreationTime().before(cert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, selfCert);
redundantCerts += 1;
selfCert = zert;
} else {
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_DUP,
log.add(LogLevel.DEBUG, LogType.MSG_KC_UID_CERT_DUP,
indent, userId);
modified = PGPPublicKey.removeCertification(modified, userId, zert);
redundantCerts += 1;
@@ -474,6 +496,10 @@ public class UncachedKeyRing {
// Replace modified key in the keyring
ring = replacePublicKey(ring, modified);
if (ring == null) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
return null;
}
indent -= 1;
}
@@ -580,8 +606,8 @@ public class UncachedKeyRing {
}
// if we already have a cert, and this one is not newer: skip it
if (selfCert != null && selfCert.getCreationTime().before(cert.getCreationTime())) {
// if we already have a cert, and this one is older: skip it
if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
redundantCerts += 1;
continue;
@@ -641,6 +667,10 @@ public class UncachedKeyRing {
}
// replace pubkey in keyring
ring = replacePublicKey(ring, modified);
if (ring == null) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
return null;
}
indent -= 1;
}
@@ -681,8 +711,9 @@ public class UncachedKeyRing {
long masterKeyId = other.getMasterKeyId();
if (getMasterKeyId() != masterKeyId) {
log.add(LogLevel.ERROR, LogType.MSG_MG_HETEROGENEOUS, indent);
if (getMasterKeyId() != masterKeyId
|| !Arrays.equals(getFingerprint(), other.getFingerprint())) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_HETEROGENEOUS, indent);
return null;
}
@@ -729,6 +760,10 @@ public class UncachedKeyRing {
} else {
// otherwise, just insert the public key
result = replacePublicKey(result, key);
if (result == null) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
return null;
}
}
continue;
}
@@ -757,6 +792,10 @@ public class UncachedKeyRing {
if (!key.isMasterKey()) {
if (modified != resultKey) {
result = replacePublicKey(result, modified);
if (result == null) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
return null;
}
}
continue;
}
@@ -781,6 +820,10 @@ public class UncachedKeyRing {
// If anything changed, save the updated (sub)key
if (modified != resultKey) {
result = replacePublicKey(result, modified);
if (result == null) {
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_SECRET_DUMMY, indent);
return null;
}
}
}
@@ -795,7 +838,7 @@ public class UncachedKeyRing {
return new UncachedKeyRing(result);
} catch (IOException e) {
log.add(LogLevel.ERROR, LogType.MSG_MG_FATAL_ENCODE, indent);
log.add(LogLevel.ERROR, LogType.MSG_MG_ERROR_ENCODE, indent);
return null;
}
@@ -826,16 +869,19 @@ public class UncachedKeyRing {
*/
private static PGPKeyRing replacePublicKey(PGPKeyRing ring, PGPPublicKey key) {
if (ring instanceof PGPPublicKeyRing) {
return PGPPublicKeyRing.insertPublicKey((PGPPublicKeyRing) ring, key);
PGPPublicKeyRing pubRing = (PGPPublicKeyRing) ring;
return PGPPublicKeyRing.insertPublicKey(pubRing, key);
} else {
PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
// TODO generate secret key with S2K dummy, if none exists!
if (sKey == null) {
Log.e(Constants.TAG, "dummy secret key generation not yet implemented");
return null;
}
sKey = PGPSecretKey.replacePublicKey(sKey, key);
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
PGPSecretKeyRing secRing = (PGPSecretKeyRing) ring;
PGPSecretKey sKey = secRing.getSecretKey(key.getKeyID());
// TODO generate secret key with S2K dummy, if none exists! for now, just die.
if (sKey == null) {
throw new RuntimeException("dummy secret key generation not yet implemented");
}
sKey = PGPSecretKey.replacePublicKey(sKey, key);
return PGPSecretKeyRing.insertSecretKey(secRing, sKey);
}
/** This method removes a subkey in a keyring.

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +18,10 @@
package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.nist.NISTNamedCurves;
import org.spongycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.spongycastle.bcpg.ECPublicBCPGKey;
import org.spongycastle.bcpg.sig.KeyFlags;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSignature;
@@ -93,10 +98,23 @@ public class UncachedPublicKey {
return mPublicKey.getAlgorithm();
}
public int getBitStrength() {
public Integer getBitStrength() {
if (isEC()) {
return null;
}
return mPublicKey.getBitStrength();
}
public String getCurveOid() {
if ( ! isEC()) {
return null;
}
if ( ! (mPublicKey.getPublicKeyPacket().getKey() instanceof ECPublicBCPGKey)) {
return null;
}
return ((ECPublicBCPGKey) mPublicKey.getPublicKeyPacket().getKey()).getCurveOID().getId();
}
/** Returns the primary user id, as indicated by the public key's self certificates.
*
* This is an expensive operation, since potentially a lot of certificates (and revocations)
@@ -185,6 +203,10 @@ public class UncachedPublicKey {
return getAlgorithm() == PGPPublicKey.DSA;
}
public boolean isEC() {
return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA;
}
@SuppressWarnings("unchecked")
// TODO make this safe
public int getKeyUsage() {

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -95,9 +96,6 @@ public class WrappedSignature {
} catch (PGPException e) {
// no matter
Log.e(Constants.TAG, "exception reading embedded signatures", e);
} catch (IOException e) {
// no matter
Log.e(Constants.TAG, "exception reading embedded signatures", e);
}
return sigs;
}
@@ -149,27 +147,17 @@ public class WrappedSignature {
}
}
public void update(byte[] data, int offset, int length) throws PgpGeneralException {
try {
mSig.update(data, offset, length);
} catch(SignatureException e) {
throw new PgpGeneralException(e);
}
public void update(byte[] data, int offset, int length) {
mSig.update(data, offset, length);
}
public void update(byte data) throws PgpGeneralException {
try {
mSig.update(data);
} catch(SignatureException e) {
throw new PgpGeneralException(e);
}
public void update(byte data) {
mSig.update(data);
}
public boolean verify() throws PgpGeneralException {
try {
return mSig.verify();
} catch(SignatureException e) {
throw new PgpGeneralException(e);
} catch(PGPException e) {
throw new PgpGeneralException(e);
}
@@ -178,8 +166,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key) throws PgpGeneralException {
try {
return mSig.verifyCertification(key);
} catch (SignatureException e) {
throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -188,8 +174,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey masterKey, PGPPublicKey subKey) throws PgpGeneralException {
try {
return mSig.verifyCertification(masterKey, subKey);
} catch (SignatureException e) {
throw new PgpGeneralException("Sign!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}
@@ -198,8 +182,6 @@ public class WrappedSignature {
boolean verifySignature(PGPPublicKey key, String uid) throws PgpGeneralException {
try {
return mSig.verifyCertification(uid, key);
} catch (SignatureException e) {
throw new PgpGeneralException("Error!", e);
} catch (PGPException e) {
throw new PgpGeneralException("Error!", e);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
* Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by