Merge pull request #553 from Valodim/split-masterKeyId

Split master key & partial fix for uid order
This commit is contained in:
Dominik Schürmann 2014-04-11 14:39:35 +02:00
commit 85bb3d9480
15 changed files with 250 additions and 250 deletions

View File

@ -51,7 +51,7 @@ public class ExportHelper {
public void deleteKey(Uri dataUri, Handler deleteHandler) { public void deleteKey(Uri dataUri, Handler deleteHandler) {
try { try {
long masterKeyId = ProviderHelper.getMasterKeyId(mActivity, dataUri); long masterKeyId = ProviderHelper.extractOrGetMasterKeyId(mActivity, dataUri);
// Create a new Messenger for the communication back // Create a new Messenger for the communication back
Messenger messenger = new Messenger(deleteHandler); Messenger messenger = new Messenger(deleteHandler);

View File

@ -122,15 +122,20 @@ public class ProviderHelper {
* Find the master key id related to a given query. The id will either be extracted from the * Find the master key id related to a given query. The id will either be extracted from the
* query, which should work for all specific /key_rings/ queries, or will be queried if it can't. * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
*/ */
public static long getMasterKeyId(Context context, Uri queryUri) throws NotFoundException { public static long extractOrGetMasterKeyId(Context context, Uri queryUri)
throws NotFoundException {
// try extracting from the uri first // try extracting from the uri first
// String firstSegment = queryUri.getPathSegments().get(1); String firstSegment = queryUri.getPathSegments().get(1);
// if(!firstSegment.equals("find")) try { if(!firstSegment.equals("find")) try {
// return Long.parseLong(firstSegment); return Long.parseLong(firstSegment);
// } catch(NumberFormatException e) { } catch(NumberFormatException e) {
// // didn't work? oh well. // didn't work? oh well.
// Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying..."); Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
// } }
return getMasterKeyId(context, queryUri);
}
public static long getMasterKeyId(Context context, Uri queryUri) throws NotFoundException {
Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER); Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER);
if(data != null) { if(data != null) {
return (Long) data; return (Long) data;
@ -461,70 +466,49 @@ public class ProviderHelper {
return ContentProviderOperation.newInsert(uri).withValues(values).build(); return ContentProviderOperation.newInsert(uri).withValues(values).build();
} }
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) { private static String getKeyRingAsArmoredString(Context context, byte[] data) throws IOException {
ArrayList<String> output = new ArrayList<String>(); Object keyRing = null;
if (data != null) {
if (masterKeyIds != null && masterKeyIds.length > 0) { keyRing = PgpConversionHelper.BytesToPGPKeyRing(data);
Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds);
if (cursor != null) {
int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
if (cursor.moveToFirst()) {
do {
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
// get actual keyring data blob and write it to ByteArrayOutputStream
try {
Object keyRing = null;
byte[] data = cursor.getBlob(dataCol);
if (data != null) {
keyRing = PgpConversionHelper.BytesToPGPKeyRing(data);
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = new ArmoredOutputStream(bos);
aos.setHeader("Version", PgpHelper.getFullVersion(context));
if (keyRing instanceof PGPSecretKeyRing) {
aos.write(((PGPSecretKeyRing) keyRing).getEncoded());
} else if (keyRing instanceof PGPPublicKeyRing) {
aos.write(((PGPPublicKeyRing) keyRing).getEncoded());
}
aos.close();
String armoredKey = bos.toString("UTF-8");
Log.d(Constants.TAG, "armoredKey:" + armoredKey);
output.add(armoredKey);
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
}
} while (cursor.moveToNext());
}
}
if (cursor != null) {
cursor.close();
}
} else {
Log.e(Constants.TAG, "No master keys given!");
} }
if (output.size() > 0) { ByteArrayOutputStream bos = new ByteArrayOutputStream();
return output; ArmoredOutputStream aos = new ArmoredOutputStream(bos);
} else { aos.setHeader("Version", PgpHelper.getFullVersion(context));
return null;
if (keyRing instanceof PGPSecretKeyRing) {
aos.write(((PGPSecretKeyRing) keyRing).getEncoded());
} else if (keyRing instanceof PGPPublicKeyRing) {
aos.write(((PGPPublicKeyRing) keyRing).getEncoded());
} }
aos.close();
String armoredKey = bos.toString("UTF-8");
Log.d(Constants.TAG, "armoredKey:" + armoredKey);
return armoredKey;
} }
private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) { public static String getKeyRingAsArmoredString(Context context, Uri uri)
Cursor cursor = null; throws NotFoundException, IOException {
if (masterKeyIds != null && masterKeyIds.length > 0) { byte[] data = (byte[]) ProviderHelper.getGenericData(
context, uri, KeyRingData.KEY_RING_DATA, ProviderHelper.FIELD_TYPE_BLOB);
return getKeyRingAsArmoredString(context, data);
}
// TODO This method is NOT ACTUALLY USED. Is this preparation for something, or just dead code?
public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds)
throws IOException {
ArrayList<String> output = new ArrayList<String>();
if (masterKeyIds == null || masterKeyIds.length == 0) {
Log.e(Constants.TAG, "No master keys given!");
return output;
}
// Build a cursor for the selected masterKeyIds
Cursor cursor = null; {
String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN ("; String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN (";
for (int i = 0; i < masterKeyIds.length; ++i) { for (int i = 0; i < masterKeyIds.length; ++i) {
if (i != 0) { if (i != 0) {
@ -536,10 +520,37 @@ public class ProviderHelper {
cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] { cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] {
KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA
}, inMasterKeyList, null, null); }, inMasterKeyList, null, null);
} }
return cursor; if (cursor != null) {
int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
if (cursor.moveToFirst()) {
do {
Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
byte[] data = cursor.getBlob(dataCol);
// get actual keyring data blob and write it to ByteArrayOutputStream
try {
output.add(getKeyRingAsArmoredString(context, data));
} catch (IOException e) {
Log.e(Constants.TAG, "IOException", e);
}
} while (cursor.moveToNext());
}
}
if (cursor != null) {
cursor.close();
}
if (output.size() > 0) {
return output;
} else {
return null;
}
} }
public static ArrayList<String> getRegisteredApiApps(Context context) { public static ArrayList<String> getRegisteredApiApps(Context context) {

View File

@ -180,7 +180,8 @@ public class AccountSettingsFragment extends Fragment implements
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
// select newly created key // select newly created key
try { try {
long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), data.getData()); long masterKeyId = ProviderHelper.extractOrGetMasterKeyId(
getActivity(), data.getData());
mSelectKeyFragment.selectKey(masterKeyId); mSelectKeyFragment.selectKey(masterKeyId);
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);

View File

@ -200,6 +200,31 @@ public class PassphraseCacheService extends Service {
return cachedPassphrase; return cachedPassphrase;
} }
public static boolean hasPassphrase(PGPSecretKeyRing secretKeyRing) {
PGPSecretKey secretKey = null;
boolean foundValidKey = false;
for (Iterator keys = secretKeyRing.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;
}
}
/** /**
* Checks if key has a passphrase. * Checks if key has a passphrase.
* *
@ -210,27 +235,7 @@ public class PassphraseCacheService extends Service {
// check if the key has no passphrase // check if the key has no passphrase
try { try {
PGPSecretKeyRing secRing = ProviderHelper.getPGPSecretKeyRing(context, secretKeyId); PGPSecretKeyRing secRing = ProviderHelper.getPGPSecretKeyRing(context, secretKeyId);
PGPSecretKey secretKey = null; return hasPassphrase(secRing);
boolean foundValidKey = false;
for (Iterator keys = secRing.getSecretKeys(); keys.hasNext(); ) {
secretKey = (PGPSecretKey) keys.next();
if (!secretKey.isPrivateKeyEmpty()) {
foundValidKey = true;
break;
}
}
if (!foundValidKey) {
return false;
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
"SC").build("".toCharArray());
PGPPrivateKey testKey = secretKey.extractPrivateKey(keyDecryptor);
if (testKey != null) {
return false;
}
} catch (PGPException e) {
// silently catch
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
} }

View File

@ -39,10 +39,12 @@ import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Toast;
import com.beardedhen.androidbootstrap.BootstrapButton; import com.beardedhen.androidbootstrap.BootstrapButton;
import com.devspark.appmsg.AppMsg; import com.devspark.appmsg.AppMsg;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
@ -287,34 +289,16 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
Log.d(Constants.TAG, "uri: " + mDataUri); Log.d(Constants.TAG, "uri: " + mDataUri);
try { try {
// get master key id using row id Uri secretUri = KeychainContract.KeyRingData.buildSecretKeyRingUri(mDataUri);
long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); mKeyRing = (PGPSecretKeyRing) ProviderHelper.getPGPKeyRing(this, secretUri);
finallyEdit(masterKeyId);
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
}
}
}
@SuppressWarnings("unchecked") PGPSecretKey masterKey = mKeyRing.getSecretKey();
private void finallyEdit(final long masterKeyId) {
if (masterKeyId != 0) {
PGPSecretKey masterKey = null;
try {
mKeyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId);
masterKey = mKeyRing.getSecretKey();
mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey()); mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey());
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) { for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(mKeyRing.getSecretKeys())) {
mKeys.add(key); mKeys.add(key);
mKeysUsages.add(-1); // get usage when view is created mKeysUsages.add(-1); // get usage when view is created
} }
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "Keyring not found with masterKeyId: " + masterKeyId);
AppMsg.makeText(this, R.string.error_no_secret_key_found, AppMsg.STYLE_ALERT).show();
// TODO
}
if (masterKey != null) {
boolean isSet = false; boolean isSet = false;
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) { for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
Log.d(Constants.TAG, "Added userId " + userId); Log.d(Constants.TAG, "Added userId " + userId);
@ -327,17 +311,23 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
} }
mUserIds.add(userId); mUserIds.add(userId);
} }
buildLayout(false);
mCurrentPassphrase = "";
mIsPassphraseSet = PassphraseCacheService.hasPassphrase(mKeyRing);
if (!mIsPassphraseSet) {
// check "no passphrase" checkbox and remove button
mNoPassphrase.setChecked(true);
mChangePassphrase.setVisibility(View.GONE);
}
} catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "Keyring not found: " + e.getMessage(), e);
Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_SHORT).show();
finish();
} }
}
mCurrentPassphrase = "";
buildLayout(false);
mIsPassphraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId);
if (!mIsPassphraseSet) {
// check "no passphrase" checkbox and remove button
mNoPassphrase.setChecked(true);
mChangePassphrase.setVisibility(View.GONE);
} }
} }

View File

@ -165,10 +165,11 @@ public class EncryptAsymmetricFragment extends Fragment {
if (preselectedEncryptionKeyIds != null) { if (preselectedEncryptionKeyIds != null) {
Vector<Long> goodIds = new Vector<Long>(); Vector<Long> goodIds = new Vector<Long>();
for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) { for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
// TODO check for available encrypt keys... is this even relevant? // TODO One query per selected key?! wtf
try { try {
long id = ProviderHelper.getMasterKeyId(getActivity(), long id = ProviderHelper.getMasterKeyId(getActivity(),
KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(preselectedEncryptionKeyIds[i])) KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(
Long.toString(preselectedEncryptionKeyIds[i]))
); );
goodIds.add(id); goodIds.add(id);
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {

View File

@ -219,12 +219,8 @@ public class ViewKeyActivity extends ActionBarActivity {
} else { } else {
// get public keyring as ascii armored string // get public keyring as ascii armored string
try { try {
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
content = ProviderHelper.getKeyRingAsArmoredString(this, uri);
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
this, new long[]{masterKeyId});
content = keyringArmored.get(0);
// Android will fail with android.os.TransactionTooLargeException if key is too big // Android will fail with android.os.TransactionTooLargeException if key is too big
// see http://www.lonestarprod.com/?p=34 // see http://www.lonestarprod.com/?p=34
@ -233,8 +229,12 @@ public class ViewKeyActivity extends ActionBarActivity {
AppMsg.STYLE_ALERT).show(); AppMsg.STYLE_ALERT).show();
return; return;
} }
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(this, R.string.error_invalid_data, AppMsg.STYLE_ALERT).show();
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
} }
} }
@ -259,16 +259,18 @@ public class ViewKeyActivity extends ActionBarActivity {
private void copyToClipboard(Uri dataUri) { private void copyToClipboard(Uri dataUri) {
// get public keyring as ascii armored string // get public keyring as ascii armored string
try { try {
long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
String keyringArmored = ProviderHelper.getKeyRingAsArmoredString(this, uri);
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( ClipboardReflection.copyToClipboard(this, keyringArmored);
this, new long[]{masterKeyId});
ClipboardReflection.copyToClipboard(this, keyringArmored.get(0));
AppMsg.makeText(this, R.string.key_copied_to_clipboard, AppMsg.STYLE_INFO) AppMsg.makeText(this, R.string.key_copied_to_clipboard, AppMsg.STYLE_INFO)
.show(); .show();
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(this, R.string.error_key_processing, AppMsg.STYLE_ALERT).show();
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(this, R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
} }
} }

View File

@ -331,11 +331,8 @@ public class ViewKeyMainFragment extends Fragment implements
} }
private void encryptToContact(Uri dataUri) { private void encryptToContact(Uri dataUri) {
// TODO preselect from uri? should be feasible without trivial query
try { try {
long keyId = ProviderHelper.getMasterKeyId(getActivity(), long keyId = ProviderHelper.extractOrGetMasterKeyId(getActivity(), dataUri);
KeyRingData.buildPublicKeyRingUri(dataUri));
long[] encryptionKeyIds = new long[]{ keyId }; long[] encryptionKeyIds = new long[]{ keyId };
Intent intent = new Intent(getActivity(), EncryptActivity.class); Intent intent = new Intent(getActivity(), EncryptActivity.class);
intent.setAction(EncryptActivity.ACTION_ENCRYPT); intent.setAction(EncryptActivity.ACTION_ENCRYPT);

View File

@ -21,9 +21,12 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.util.SparseArray; import android.util.SparseArray;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPKeyRing;
import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
@ -46,31 +49,19 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public int bitStrength; public int bitStrength;
public String algorithm; public String algorithm;
public boolean secretKey; public boolean secretKey;
public String mPrimaryUserId;
private boolean mSelected; private boolean mSelected;
private byte[] mBytes = new byte[]{}; private byte[] mBytes = new byte[]{};
public ImportKeysListEntry(ImportKeysListEntry b) {
this.userIds = b.userIds;
this.keyId = b.keyId;
this.revoked = b.revoked;
this.date = b.date;
this.fingerPrintHex = b.fingerPrintHex;
this.keyIdHex = b.keyIdHex;
this.bitStrength = b.bitStrength;
this.algorithm = b.algorithm;
this.secretKey = b.secretKey;
this.mSelected = b.mSelected;
this.mBytes = b.mBytes;
}
public int describeContents() { public int describeContents() {
return 0; return 0;
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPrimaryUserId);
dest.writeStringList(userIds); dest.writeStringList(userIds);
dest.writeLong(keyId); dest.writeLong(keyId);
dest.writeByte((byte) (revoked ? 1 : 0)); dest.writeByte((byte) (revoked ? 1 : 0));
@ -88,6 +79,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() { public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
public ImportKeysListEntry createFromParcel(final Parcel source) { public ImportKeysListEntry createFromParcel(final Parcel source) {
ImportKeysListEntry vr = new ImportKeysListEntry(); ImportKeysListEntry vr = new ImportKeysListEntry();
vr.mPrimaryUserId = source.readString();
vr.userIds = new ArrayList<String>(); vr.userIds = new ArrayList<String>();
source.readStringList(vr.userIds); source.readStringList(vr.userIds);
vr.keyId = source.readLong(); vr.keyId = source.readLong();
@ -198,6 +190,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.userIds = userIds; this.userIds = userIds;
} }
public String getPrimaryUserId() {
return mPrimaryUserId;
}
public void setPrimaryUserId(String uid) {
mPrimaryUserId = uid;
}
/** /**
* Constructor for later querying from keyserver * Constructor for later querying from keyserver
*/ */
@ -229,20 +229,39 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
} else { } else {
secretKey = false; secretKey = false;
} }
PGPPublicKey key = pgpKeyRing.getPublicKey();
userIds = new ArrayList<String>(); userIds = new ArrayList<String>();
for (String userId : new IterableIterator<String>(pgpKeyRing.getPublicKey().getUserIDs())) { for (String userId : new IterableIterator<String>(key.getUserIDs())) {
userIds.add(userId); userIds.add(userId);
for(PGPSignature sig : new IterableIterator<PGPSignature>(key.getSignaturesForID(userId))) {
if(sig.getHashedSubPackets().hasSubpacket(SignatureSubpacketTags.PRIMARY_USER_ID)) {
try {
// make sure it's actually valid
sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME), key);
if (sig.verifyCertification(userId, key)) {
mPrimaryUserId = userId;
}
} catch(Exception e) {
// nothing bad happens, the key is just not considered the primary key id
}
}
}
}
// if there was no user id flagged as primary, use the first one
if(mPrimaryUserId == null) {
mPrimaryUserId = userIds.get(0);
} }
this.keyId = pgpKeyRing.getPublicKey().getKeyID(); this.keyId = key.getKeyID();
this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId);
this.revoked = pgpKeyRing.getPublicKey().isRevoked(); this.revoked = key.isRevoked();
this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(pgpKeyRing.getPublicKey() this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
.getFingerprint()); this.bitStrength = key.getBitStrength();
this.bitStrength = pgpKeyRing.getPublicKey().getBitStrength(); final int algorithm = key.getAlgorithm();
final int algorithm = pgpKeyRing.getPublicKey().getAlgorithm();
this.algorithm = getAlgorithmFromId(algorithm); this.algorithm = getAlgorithmFromId(algorithm);
} }

View File

@ -28,14 +28,19 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.QrCodeUtils;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
public class ShareQrCodeDialogFragment extends DialogFragment { public class ShareQrCodeDialogFragment extends DialogFragment {
@ -77,7 +82,6 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
mFingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY); mFingerprintOnly = getArguments().getBoolean(ARG_FINGERPRINT_ONLY);
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
alert.setTitle(R.string.share_qr_code_dialog_title); alert.setTitle(R.string.share_qr_code_dialog_title);
LayoutInflater inflater = activity.getLayoutInflater(); LayoutInflater inflater = activity.getLayoutInflater();
@ -95,7 +99,8 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
getActivity(), KeyRings.buildUnifiedKeyRingUri(dataUri), getActivity(), KeyRings.buildUnifiedKeyRingUri(dataUri),
KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
if(blob == null) { if(blob == null) {
// TODO error handling?! Log.e(Constants.TAG, "key not found!");
AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
return null; return null;
} }
@ -106,20 +111,18 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
} else { } else {
mText.setText(R.string.share_qr_code_dialog_start); mText.setText(R.string.share_qr_code_dialog_start);
// TODO works, but
long masterKeyId = 0;
try { try {
masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri);
content = ProviderHelper.getKeyRingAsArmoredString(getActivity(), uri);
} catch (IOException e) {
Log.e(Constants.TAG, "error processing key!", e);
AppMsg.makeText(getActivity(), R.string.error_invalid_data, AppMsg.STYLE_ALERT).show();
return null;
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e); Log.e(Constants.TAG, "key not found!", e);
AppMsg.makeText(getActivity(), R.string.error_key_not_found, AppMsg.STYLE_ALERT).show();
return null;
} }
// get public keyring as ascii armored string
ArrayList<String> keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
getActivity(), new long[] { masterKeyId });
// TODO: binary?
content = keyringArmored.get(0);
// OnClickListener are set in onResume to prevent automatic dismissing of Dialogs // OnClickListener are set in onResume to prevent automatic dismissing of Dialogs
// http://bit.ly/O5vfaR // http://bit.ly/O5vfaR

View File

@ -294,6 +294,7 @@ public class HkpKeyServer extends KeyServer {
userIds.add(tmp); userIds.add(tmp);
} }
entry.setUserIds(userIds); entry.setUserIds(userIds);
entry.setPrimaryUserId(userIds.get(0));
results.add(entry); results.add(entry);
} }

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/drawer_list"/>
</android.support.v4.widget.DrawerLayout>
<include layout="@layout/import_keys_content"/>
</FrameLayout>

View File

@ -1,11 +1,50 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout" xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:id="@+id/content_frame"
android:layout_height="match_parent" > android:layout_marginLeft="@dimen/drawer_content_padding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<include layout="@layout/import_keys_content"/> <FrameLayout
android:id="@+id/import_navigation_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp" />
<include layout="@layout/drawer_list" /> <LinearLayout
android:id="@+id/import_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">
</android.support.v4.widget.DrawerLayout> <com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/import_import"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:text="@string/import_import"
bootstrapbutton:bb_icon_left="fa-download"
bootstrapbutton:bb_type="info" />
</LinearLayout>
<FrameLayout
android:id="@+id/import_keys_list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/import_footer"
android:layout_alignParentLeft="true"
android:layout_below="@+id/import_navigation_fragment"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp" />
</RelativeLayout>

View File

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bootstrapbutton="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_frame"
android:layout_marginLeft="@dimen/drawer_content_padding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<FrameLayout
android:id="@+id/import_navigation_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp" />
<LinearLayout
android:id="@+id/import_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<com.beardedhen.androidbootstrap.BootstrapButton
android:id="@+id/import_import"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:text="@string/import_import"
bootstrapbutton:bb_icon_left="fa-download"
bootstrapbutton:bb_type="info" />
</LinearLayout>
<FrameLayout
android:id="@+id/import_keys_list_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/import_footer"
android:layout_alignParentLeft="true"
android:layout_below="@+id/import_navigation_fragment"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp" />
</RelativeLayout>

View File

@ -525,5 +525,7 @@
<string name="label_cert_type">Type</string> <string name="label_cert_type">Type</string>
<string name="can_certify">can certify</string> <string name="can_certify">can certify</string>
<string name="can_certify_not">cannot certify</string> <string name="can_certify_not">cannot certify</string>
<string name="error_key_not_found">Key not found!</string>
<string name="error_key_processing">Error processing key!</string>
</resources> </resources>