mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-30 12:32:17 -05:00
add ecc support
This commit is contained in:
parent
08bdb0c5b9
commit
783dae8804
@ -36,11 +36,11 @@ import org.spongycastle.bcpg.UserIDPacket;
|
|||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
|
|
||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringBuilder;
|
import org.sufficientlysecure.keychain.support.KeyringBuilder;
|
||||||
@ -78,11 +78,11 @@ public class PgpKeyOperationTest {
|
|||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.DSA, 1024, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
|
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
|
|
||||||
parcel.mAddUserIds.add("twi");
|
parcel.mAddUserIds.add("twi");
|
||||||
parcel.mAddUserIds.add("pink");
|
parcel.mAddUserIds.add("pink");
|
||||||
@ -120,7 +120,7 @@ public class PgpKeyOperationTest {
|
|||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(256)+255, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, new Random().nextInt(256)+255, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddUserIds.add("shy");
|
parcel.mAddUserIds.add("shy");
|
||||||
parcel.mNewPassphrase = passphrase;
|
parcel.mNewPassphrase = passphrase;
|
||||||
|
|
||||||
@ -131,18 +131,18 @@ public class PgpKeyOperationTest {
|
|||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.ELGAMAL, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddUserIds.add("shy");
|
parcel.mAddUserIds.add("shy");
|
||||||
parcel.mNewPassphrase = passphrase;
|
parcel.mNewPassphrase = passphrase;
|
||||||
|
|
||||||
assertFailure("creating ring with ElGamal master key should fail", parcel,
|
assertFailure("creating ring with ElGamal master key should fail", parcel,
|
||||||
LogType.MSG_CR_ERROR_MASTER_ELGAMAL);
|
LogType.MSG_CR_ERROR_FLAGS_ELGAMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, null));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, null));
|
||||||
parcel.mAddUserIds.add("lotus");
|
parcel.mAddUserIds.add("lotus");
|
||||||
parcel.mNewPassphrase = passphrase;
|
parcel.mNewPassphrase = passphrase;
|
||||||
|
|
||||||
@ -153,18 +153,7 @@ public class PgpKeyOperationTest {
|
|||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
12345, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddUserIds.add("shy");
|
|
||||||
parcel.mNewPassphrase = passphrase;
|
|
||||||
|
|
||||||
assertFailure("creating ring with bad algorithm choice should fail", parcel,
|
|
||||||
LogType.MSG_CR_ERROR_UNKNOWN_ALGO);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
parcel.reset();
|
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
|
|
||||||
parcel.mAddUserIds.add("shy");
|
parcel.mAddUserIds.add("shy");
|
||||||
parcel.mNewPassphrase = passphrase;
|
parcel.mNewPassphrase = passphrase;
|
||||||
|
|
||||||
@ -175,7 +164,7 @@ public class PgpKeyOperationTest {
|
|||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mNewPassphrase = passphrase;
|
parcel.mNewPassphrase = passphrase;
|
||||||
|
|
||||||
assertFailure("creating ring without user ids should fail", parcel,
|
assertFailure("creating ring without user ids should fail", parcel,
|
||||||
@ -199,7 +188,7 @@ public class PgpKeyOperationTest {
|
|||||||
public void testMasterFlags() throws Exception {
|
public void testMasterFlags() throws Exception {
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddUserIds.add("luna");
|
parcel.mAddUserIds.add("luna");
|
||||||
ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
|
ring = assertCreateSuccess("creating ring with master key flags must succeed", parcel);
|
||||||
|
|
||||||
@ -313,7 +302,7 @@ public class PgpKeyOperationTest {
|
|||||||
long expiry = new Date().getTime() / 1000 + 159;
|
long expiry = new Date().getTime() / 1000 + 159;
|
||||||
int flags = KeyFlags.SIGN_DATA;
|
int flags = KeyFlags.SIGN_DATA;
|
||||||
int bits = 1024 + new Random().nextInt(8);
|
int bits = 1024 + new Random().nextInt(8);
|
||||||
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, bits, flags, expiry));
|
parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, bits, null, flags, expiry));
|
||||||
|
|
||||||
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
|
UncachedKeyRing modified = applyModificationWithChecks(parcel, ring, onlyA, onlyB);
|
||||||
|
|
||||||
@ -349,12 +338,12 @@ public class PgpKeyOperationTest {
|
|||||||
Assert.assertEquals("added key must have expected flags",
|
Assert.assertEquals("added key must have expected flags",
|
||||||
flags, newKey.getKeyUsage());
|
flags, newKey.getKeyUsage());
|
||||||
Assert.assertEquals("added key must have expected bitsize",
|
Assert.assertEquals("added key must have expected bitsize",
|
||||||
bits, newKey.getBitStrength());
|
bits, (int) newKey.getBitStrength());
|
||||||
|
|
||||||
{ // bad keysize should fail
|
{ // bad keysize should fail
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SubkeyAdd(
|
parcel.mAddSubKeys.add(new SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, new Random().nextInt(512), KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, new Random().nextInt(512), null, KeyFlags.SIGN_DATA, 0L));
|
||||||
assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
|
assertModifyFailure("creating a subkey with keysize < 512 should fail", ring, parcel,
|
||||||
LogType.MSG_CR_ERROR_KEYSIZE_512);
|
LogType.MSG_CR_ERROR_KEYSIZE_512);
|
||||||
|
|
||||||
@ -363,7 +352,7 @@ public class PgpKeyOperationTest {
|
|||||||
{
|
{
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, null));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, null));
|
||||||
|
|
||||||
assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
|
assertModifyFailure("creating master key with null expiry should fail", ring, parcel,
|
||||||
LogType.MSG_MF_ERROR_NULL_EXPIRY);
|
LogType.MSG_MF_ERROR_NULL_EXPIRY);
|
||||||
@ -371,7 +360,7 @@ public class PgpKeyOperationTest {
|
|||||||
|
|
||||||
{ // a past expiry should fail
|
{ // a past expiry should fail
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA,
|
parcel.mAddSubKeys.add(new SubkeyAdd(Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA,
|
||||||
new Date().getTime()/1000-10));
|
new Date().getTime()/1000-10));
|
||||||
assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
|
assertModifyFailure("creating subkey with past expiry date should fail", ring, parcel,
|
||||||
LogType.MSG_MF_ERROR_PAST_EXPIRY);
|
LogType.MSG_MF_ERROR_PAST_EXPIRY);
|
||||||
|
@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
|
|
||||||
@ -85,11 +86,11 @@ public class UncachedKeyringCanonicalizeTest {
|
|||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
|
|
||||||
parcel.mAddUserIds.add("twi");
|
parcel.mAddUserIds.add("twi");
|
||||||
parcel.mAddUserIds.add("pink");
|
parcel.mAddUserIds.add("pink");
|
||||||
@ -298,7 +299,7 @@ public class UncachedKeyringCanonicalizeTest {
|
|||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddUserIds.add("trix");
|
parcel.mAddUserIds.add("trix");
|
||||||
PgpKeyOperation op = new PgpKeyOperation(null);
|
PgpKeyOperation op = new PgpKeyOperation(null);
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
@ -85,9 +86,9 @@ public class UncachedKeyringMergeTest {
|
|||||||
{
|
{
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
|
|
||||||
parcel.mAddUserIds.add("twi");
|
parcel.mAddUserIds.add("twi");
|
||||||
parcel.mAddUserIds.add("pink");
|
parcel.mAddUserIds.add("pink");
|
||||||
@ -104,7 +105,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
{
|
{
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
|
|
||||||
parcel.mAddUserIds.add("shy");
|
parcel.mAddUserIds.add("shy");
|
||||||
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
// passphrase is tested in PgpKeyOperationTest, just use empty here
|
||||||
@ -210,7 +211,7 @@ public class UncachedKeyringMergeTest {
|
|||||||
|
|
||||||
parcel.reset();
|
parcel.reset();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedA = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
||||||
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
modifiedB = op.modifySecretKeyRing(secretRing, parcel, "").getRing();
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ import org.sufficientlysecure.keychain.Constants;
|
|||||||
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -55,11 +56,11 @@ public class UncachedKeyringTest {
|
|||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.CERTIFY_OTHER, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
PublicKeyAlgorithmTags.RSA_GENERAL, 1024, KeyFlags.ENCRYPT_COMMS, 0L));
|
Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
|
|
||||||
parcel.mAddUserIds.add("twi");
|
parcel.mAddUserIds.add("twi");
|
||||||
parcel.mAddUserIds.add("pink");
|
parcel.mAddUserIds.add("pink");
|
||||||
|
@ -283,7 +283,7 @@ public class HkpKeyserver extends Keyserver {
|
|||||||
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
|
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
|
||||||
|
|
||||||
final int algorithmId = Integer.decode(matcher.group(2));
|
final int algorithmId = Integer.decode(matcher.group(2));
|
||||||
entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId));
|
entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId, null, null));
|
||||||
|
|
||||||
// group 1 contains the full fingerprint (v4) or the long key id if available
|
// group 1 contains the full fingerprint (v4) or the long key id if available
|
||||||
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
|
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
|
||||||
|
@ -39,7 +39,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||||||
private boolean mExpired;
|
private boolean mExpired;
|
||||||
private Date mDate; // TODO: not displayed
|
private Date mDate; // TODO: not displayed
|
||||||
private String mFingerprintHex;
|
private String mFingerprintHex;
|
||||||
private int mBitStrength;
|
private Integer mBitStrength;
|
||||||
|
private String mCurveOid;
|
||||||
private String mAlgorithm;
|
private String mAlgorithm;
|
||||||
private boolean mSecretKey;
|
private boolean mSecretKey;
|
||||||
private String mPrimaryUserId;
|
private String mPrimaryUserId;
|
||||||
@ -162,10 +163,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||||||
this.mFingerprintHex = fingerprintHex;
|
this.mFingerprintHex = fingerprintHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBitStrength() {
|
public Integer getBitStrength() {
|
||||||
return mBitStrength;
|
return mBitStrength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCurveOid() {
|
||||||
|
return mCurveOid;
|
||||||
|
}
|
||||||
|
|
||||||
public void setBitStrength(int bitStrength) {
|
public void setBitStrength(int bitStrength) {
|
||||||
this.mBitStrength = bitStrength;
|
this.mBitStrength = bitStrength;
|
||||||
}
|
}
|
||||||
@ -258,13 +263,15 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||||||
mPrimaryUserId = mUserIds.get(0);
|
mPrimaryUserId = mUserIds.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mKeyId = key.getKeyId();
|
mKeyId = key.getKeyId();
|
||||||
this.mKeyIdHex = PgpKeyHelper.convertKeyIdToHex(mKeyId);
|
mKeyIdHex = PgpKeyHelper.convertKeyIdToHex(mKeyId);
|
||||||
|
|
||||||
this.mRevoked = key.isRevoked();
|
mRevoked = key.isRevoked();
|
||||||
this.mFingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
|
mFingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
|
||||||
this.mBitStrength = key.getBitStrength();
|
mBitStrength = key.getBitStrength();
|
||||||
|
mCurveOid = key.getCurveOid();
|
||||||
final int algorithm = key.getAlgorithm();
|
final int algorithm = key.getAlgorithm();
|
||||||
this.mAlgorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm);
|
mAlgorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm, mBitStrength, mCurveOid);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ public class KeybaseKeyserver extends Keyserver {
|
|||||||
entry.setExtraData(username);
|
entry.setExtraData(username);
|
||||||
|
|
||||||
final int algorithmId = match.getAlgorithmId();
|
final int algorithmId = match.getAlgorithmId();
|
||||||
entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId));
|
entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId, null, null));
|
||||||
final int bitStrength = match.getBitStrength();
|
final int bitStrength = match.getBitStrength();
|
||||||
entry.setBitStrength(bitStrength);
|
entry.setBitStrength(bitStrength);
|
||||||
|
|
||||||
|
@ -24,10 +24,16 @@ import android.text.Spannable;
|
|||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.style.ForegroundColorSpan;
|
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.bcpg.PublicKeyAlgorithmTags;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
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 org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
import java.security.DigestException;
|
import java.security.DigestException;
|
||||||
@ -37,18 +43,14 @@ import java.util.Locale;
|
|||||||
|
|
||||||
public class PgpKeyHelper {
|
public class PgpKeyHelper {
|
||||||
|
|
||||||
public static String getAlgorithmInfo(int algorithm) {
|
public static String getAlgorithmInfo(int algorithm, Integer keySize, String oid) {
|
||||||
return getAlgorithmInfo(null, algorithm, 0);
|
return getAlgorithmInfo(null, algorithm, keySize, oid);
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAlgorithmInfo(Context context, int algorithm) {
|
|
||||||
return getAlgorithmInfo(context, algorithm, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on <a href="http://tools.ietf.org/html/rfc2440#section-9.1">OpenPGP Message Format</a>
|
* 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;
|
String algorithmStr;
|
||||||
|
|
||||||
switch (algorithm) {
|
switch (algorithm) {
|
||||||
@ -69,10 +71,19 @@ public class PgpKeyHelper {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PublicKeyAlgorithmTags.ECDSA:
|
case PublicKeyAlgorithmTags.ECDSA: {
|
||||||
|
if (oid == null) {
|
||||||
|
return "ECDSA";
|
||||||
|
}
|
||||||
|
String oidName = PgpKeyHelper.getCurveInfo(context, oid);
|
||||||
|
return "ECDSA (" + oidName + ")";
|
||||||
|
}
|
||||||
case PublicKeyAlgorithmTags.ECDH: {
|
case PublicKeyAlgorithmTags.ECDH: {
|
||||||
algorithmStr = "ECC";
|
if (oid == null) {
|
||||||
break;
|
return "ECDH";
|
||||||
|
}
|
||||||
|
String oidName = PgpKeyHelper.getCurveInfo(context, oid);
|
||||||
|
return "ECDH (" + oidName + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
@ -90,6 +101,106 @@ public class PgpKeyHelper {
|
|||||||
return algorithmStr;
|
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 (optional: with whitespaces after 4 characters)
|
* Converts fingerprint to hex (optional: with whitespaces after 4 characters)
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -20,12 +20,12 @@ package org.sufficientlysecure.keychain.pgp;
|
|||||||
|
|
||||||
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
import org.spongycastle.bcpg.CompressionAlgorithmTags;
|
||||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||||
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
|
|
||||||
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
|
import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags;
|
||||||
import org.spongycastle.bcpg.sig.Features;
|
import org.spongycastle.bcpg.sig.Features;
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.jce.spec.ElGamalParameterSpec;
|
import org.spongycastle.jce.spec.ElGamalParameterSpec;
|
||||||
import org.spongycastle.openpgp.PGPException;
|
import org.spongycastle.openpgp.PGPException;
|
||||||
|
import org.spongycastle.openpgp.PGPKeyFlags;
|
||||||
import org.spongycastle.openpgp.PGPKeyPair;
|
import org.spongycastle.openpgp.PGPKeyPair;
|
||||||
import org.spongycastle.openpgp.PGPPrivateKey;
|
import org.spongycastle.openpgp.PGPPrivateKey;
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
@ -52,6 +52,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
|
|||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
import org.sufficientlysecure.keychain.service.OperationResults.EditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
@ -66,6 +68,7 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -155,31 +158,65 @@ public class PgpKeyOperation {
|
|||||||
mProgress.peek().setProgress(message, current, 100);
|
mProgress.peek().setProgress(message, current, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ECGenParameterSpec getEccParameterSpec(Curve curve) {
|
||||||
|
switch (curve) {
|
||||||
|
case NIST_P256: return new ECGenParameterSpec("P-256");
|
||||||
|
case NIST_P384: return new ECGenParameterSpec("P-384");
|
||||||
|
case NIST_P521: return new ECGenParameterSpec("P-521");
|
||||||
|
|
||||||
|
// @see SaveKeyringParcel
|
||||||
|
// case BRAINPOOL_P256: return new ECGenParameterSpec("brainpoolp256r1");
|
||||||
|
// case BRAINPOOL_P384: return new ECGenParameterSpec("brainpoolp384r1");
|
||||||
|
// case BRAINPOOL_P512: return new ECGenParameterSpec("brainpoolp512r1");
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Invalid choice! (can't happen)");
|
||||||
|
}
|
||||||
|
|
||||||
/** Creates new secret key. */
|
/** Creates new secret key. */
|
||||||
private PGPKeyPair createKey(int algorithmChoice, int keySize, OperationLog log, int indent) {
|
private PGPKeyPair createKey(SubkeyAdd add, OperationLog log, int indent) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (keySize < 512) {
|
// Some safety checks
|
||||||
|
if (add.mAlgorithm == Algorithm.ECDH || add.mAlgorithm == Algorithm.ECDSA) {
|
||||||
|
if (add.mCurve == null) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_CURVE, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (add.mKeySize == null) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_KEYSIZE, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (add.mKeySize < 512) {
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_KEYSIZE_512, indent);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int algorithm;
|
int algorithm;
|
||||||
KeyPairGenerator keyGen;
|
KeyPairGenerator keyGen;
|
||||||
|
|
||||||
switch (algorithmChoice) {
|
switch (add.mAlgorithm) {
|
||||||
case PublicKeyAlgorithmTags.DSA: {
|
case DSA: {
|
||||||
|
if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_DSA, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
progress(R.string.progress_generating_dsa, 30);
|
progress(R.string.progress_generating_dsa, 30);
|
||||||
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
keyGen = KeyPairGenerator.getInstance("DSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
keyGen.initialize(keySize, new SecureRandom());
|
keyGen.initialize(add.mKeySize, new SecureRandom());
|
||||||
algorithm = PGPPublicKey.DSA;
|
algorithm = PGPPublicKey.DSA;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: {
|
case ELGAMAL: {
|
||||||
|
if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ELGAMAL, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
progress(R.string.progress_generating_elgamal, 30);
|
progress(R.string.progress_generating_elgamal, 30);
|
||||||
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
BigInteger p = Primes.getBestPrime(keySize);
|
BigInteger p = Primes.getBestPrime(add.mKeySize);
|
||||||
BigInteger g = new BigInteger("2");
|
BigInteger g = new BigInteger("2");
|
||||||
|
|
||||||
ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
|
ElGamalParameterSpec elParams = new ElGamalParameterSpec(p, g);
|
||||||
@ -189,15 +226,44 @@ public class PgpKeyOperation {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PublicKeyAlgorithmTags.RSA_GENERAL: {
|
case RSA: {
|
||||||
progress(R.string.progress_generating_rsa, 30);
|
progress(R.string.progress_generating_rsa, 30);
|
||||||
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
keyGen = KeyPairGenerator.getInstance("RSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
keyGen.initialize(keySize, new SecureRandom());
|
keyGen.initialize(add.mKeySize, new SecureRandom());
|
||||||
|
|
||||||
algorithm = PGPPublicKey.RSA_GENERAL;
|
algorithm = PGPPublicKey.RSA_GENERAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ECDSA: {
|
||||||
|
if ((add.mFlags & (PGPKeyFlags.CAN_ENCRYPT_COMMS | PGPKeyFlags.CAN_ENCRYPT_STORAGE)) > 0) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDSA, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
progress(R.string.progress_generating_ecdsa, 30);
|
||||||
|
ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
|
||||||
|
keyGen = KeyPairGenerator.getInstance("ECDSA", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
keyGen.initialize(ecParamSpec, new SecureRandom());
|
||||||
|
|
||||||
|
algorithm = PGPPublicKey.ECDSA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ECDH: {
|
||||||
|
// make sure there are no sign or certify flags set
|
||||||
|
if ((add.mFlags & (PGPKeyFlags.CAN_SIGN | PGPKeyFlags.CAN_CERTIFY)) > 0) {
|
||||||
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_FLAGS_ECDH, indent);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
progress(R.string.progress_generating_ecdh, 30);
|
||||||
|
ECGenParameterSpec ecParamSpec = getEccParameterSpec(add.mCurve);
|
||||||
|
keyGen = KeyPairGenerator.getInstance("ECDH", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
keyGen.initialize(ecParamSpec, new SecureRandom());
|
||||||
|
|
||||||
|
algorithm = PGPPublicKey.ECDH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
|
||||||
return null;
|
return null;
|
||||||
@ -210,7 +276,8 @@ public class PgpKeyOperation {
|
|||||||
} catch(NoSuchProviderException e) {
|
} catch(NoSuchProviderException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch(NoSuchAlgorithmException e) {
|
} catch(NoSuchAlgorithmException e) {
|
||||||
throw new RuntimeException(e);
|
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent);
|
||||||
|
return null;
|
||||||
} catch(InvalidAlgorithmParameterException e) {
|
} catch(InvalidAlgorithmParameterException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
} catch(PGPException e) {
|
} catch(PGPException e) {
|
||||||
@ -252,13 +319,8 @@ public class PgpKeyOperation {
|
|||||||
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
|
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add.mAlgorithm == PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT) {
|
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_MASTER_ELGAMAL, indent);
|
|
||||||
return new EditKeyResult(EditKeyResult.RESULT_ERROR, log, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
subProgressPush(10, 30);
|
subProgressPush(10, 30);
|
||||||
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
|
PGPKeyPair keyPair = createKey(add, log, indent);
|
||||||
subProgressPop();
|
subProgressPop();
|
||||||
|
|
||||||
// return null if this failed (an error will already have been logged by createKey)
|
// return null if this failed (an error will already have been logged by createKey)
|
||||||
@ -690,8 +752,8 @@ public class PgpKeyOperation {
|
|||||||
|
|
||||||
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
|
progress(R.string.progress_modify_subkeyadd, (i-1) * (100 / saveParcel.mAddSubKeys.size()));
|
||||||
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
|
SaveKeyringParcel.SubkeyAdd add = saveParcel.mAddSubKeys.get(i);
|
||||||
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent, Integer.toString(add.mKeysize),
|
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent,
|
||||||
PgpKeyHelper.getAlgorithmInfo(add.mAlgorithm) );
|
PgpKeyHelper.getAlgorithmInfo(add.mAlgorithm, add.mKeySize, add.mCurve) );
|
||||||
|
|
||||||
if (add.mExpiry == null) {
|
if (add.mExpiry == null) {
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
|
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_NULL_EXPIRY, indent +1);
|
||||||
@ -708,7 +770,7 @@ public class PgpKeyOperation {
|
|||||||
(i-1) * (100 / saveParcel.mAddSubKeys.size()),
|
(i-1) * (100 / saveParcel.mAddSubKeys.size()),
|
||||||
i * (100 / saveParcel.mAddSubKeys.size())
|
i * (100 / saveParcel.mAddSubKeys.size())
|
||||||
);
|
);
|
||||||
PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize, log, indent);
|
PGPKeyPair keyPair = createKey(add, log, indent);
|
||||||
subProgressPop();
|
subProgressPop();
|
||||||
if (keyPair == null) {
|
if (keyPair == null) {
|
||||||
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent +1);
|
log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_PGP, indent +1);
|
||||||
|
@ -37,7 +37,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
|
|||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults;
|
|
||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
@ -58,7 +57,8 @@ import java.util.TreeSet;
|
|||||||
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
|
* This class and its relatives UncachedPublicKey and UncachedSecretKey are
|
||||||
* used to move around pgp key rings in non crypto related (UI, mostly) code.
|
* 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,
|
* 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
|
* This class is also special in that it can hold either the PGPPublicKeyRing
|
||||||
* or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are
|
* or PGPSecretKeyRing derivate of the PGPKeyRing class, since these are
|
||||||
@ -591,7 +591,7 @@ public class UncachedKeyRing {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we already have a cert, and this one is not newer: skip it
|
// if we already have a cert, and this one is older: skip it
|
||||||
if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
|
if (selfCert != null && cert.getCreationTime().before(selfCert.getCreationTime())) {
|
||||||
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
|
log.add(LogLevel.DEBUG, LogType.MSG_KC_SUB_DUP, indent);
|
||||||
redundantCerts += 1;
|
redundantCerts += 1;
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.pgp;
|
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.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.openpgp.PGPPublicKey;
|
import org.spongycastle.openpgp.PGPPublicKey;
|
||||||
import org.spongycastle.openpgp.PGPSignature;
|
import org.spongycastle.openpgp.PGPSignature;
|
||||||
@ -94,10 +98,23 @@ public class UncachedPublicKey {
|
|||||||
return mPublicKey.getAlgorithm();
|
return mPublicKey.getAlgorithm();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBitStrength() {
|
public Integer getBitStrength() {
|
||||||
|
if (isEC()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return mPublicKey.getBitStrength();
|
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.
|
/** 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)
|
* This is an expensive operation, since potentially a lot of certificates (and revocations)
|
||||||
@ -186,6 +203,10 @@ public class UncachedPublicKey {
|
|||||||
return getAlgorithm() == PGPPublicKey.DSA;
|
return getAlgorithm() == PGPPublicKey.DSA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEC() {
|
||||||
|
return getAlgorithm() == PGPPublicKey.ECDH || getAlgorithm() == PGPPublicKey.ECDSA;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// TODO make this safe
|
// TODO make this safe
|
||||||
public int getKeyUsage() {
|
public int getKeyUsage() {
|
||||||
|
@ -39,6 +39,7 @@ public class KeychainContract {
|
|||||||
String FINGERPRINT = "fingerprint";
|
String FINGERPRINT = "fingerprint";
|
||||||
|
|
||||||
String KEY_SIZE = "key_size";
|
String KEY_SIZE = "key_size";
|
||||||
|
String KEY_CURVE_OID = "key_curve_oid";
|
||||||
String CAN_SIGN = "can_sign";
|
String CAN_SIGN = "can_sign";
|
||||||
String CAN_ENCRYPT = "can_encrypt";
|
String CAN_ENCRYPT = "can_encrypt";
|
||||||
String CAN_CERTIFY = "can_certify";
|
String CAN_CERTIFY = "can_certify";
|
||||||
|
@ -52,7 +52,7 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class KeychainDatabase extends SQLiteOpenHelper {
|
public class KeychainDatabase extends SQLiteOpenHelper {
|
||||||
private static final String DATABASE_NAME = "openkeychain.db";
|
private static final String DATABASE_NAME = "openkeychain.db";
|
||||||
private static final int DATABASE_VERSION = 2;
|
private static final int DATABASE_VERSION = 3;
|
||||||
static Boolean apgHack = false;
|
static Boolean apgHack = false;
|
||||||
|
|
||||||
public interface Tables {
|
public interface Tables {
|
||||||
@ -86,6 +86,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
+ KeysColumns.KEY_ID + " INTEGER, "
|
+ KeysColumns.KEY_ID + " INTEGER, "
|
||||||
+ KeysColumns.KEY_SIZE + " INTEGER, "
|
+ KeysColumns.KEY_SIZE + " INTEGER, "
|
||||||
|
+ KeysColumns.KEY_CURVE_OID + " TEXT, "
|
||||||
+ KeysColumns.ALGORITHM + " INTEGER, "
|
+ KeysColumns.ALGORITHM + " INTEGER, "
|
||||||
+ KeysColumns.FINGERPRINT + " BLOB, "
|
+ KeysColumns.FINGERPRINT + " BLOB, "
|
||||||
|
|
||||||
@ -202,11 +203,18 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
if (oldVersion == 1) {
|
|
||||||
// add has_secret for all who are upgrading from a beta version
|
// add has_secret for all who are upgrading from a beta version
|
||||||
|
switch (oldVersion) {
|
||||||
|
case 1:
|
||||||
try {
|
try {
|
||||||
db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");
|
db.execSQL("ALTER TABLE keys ADD COLUMN has_secret BOOLEAN");
|
||||||
} catch (Exception e) {
|
} catch(Exception e){
|
||||||
|
// never mind, the column probably already existed
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
try {
|
||||||
|
db.execSQL("ALTER TABLE keys ADD COLUMN " + KeysColumns.KEY_CURVE_OID + " TEXT");
|
||||||
|
} catch(Exception e){
|
||||||
// never mind, the column probably already existed
|
// never mind, the column probably already existed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
|
projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
|
||||||
projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID);
|
projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID);
|
||||||
projectionMap.put(KeyRings.KEY_SIZE, Tables.KEYS + "." + Keys.KEY_SIZE);
|
projectionMap.put(KeyRings.KEY_SIZE, Tables.KEYS + "." + Keys.KEY_SIZE);
|
||||||
|
projectionMap.put(KeyRings.KEY_CURVE_OID, Tables.KEYS + "." + Keys.KEY_CURVE_OID);
|
||||||
projectionMap.put(KeyRings.IS_REVOKED, Tables.KEYS + "." + Keys.IS_REVOKED);
|
projectionMap.put(KeyRings.IS_REVOKED, Tables.KEYS + "." + Keys.IS_REVOKED);
|
||||||
projectionMap.put(KeyRings.CAN_CERTIFY, Tables.KEYS + "." + Keys.CAN_CERTIFY);
|
projectionMap.put(KeyRings.CAN_CERTIFY, Tables.KEYS + "." + Keys.CAN_CERTIFY);
|
||||||
projectionMap.put(KeyRings.CAN_ENCRYPT, Tables.KEYS + "." + Keys.CAN_ENCRYPT);
|
projectionMap.put(KeyRings.CAN_ENCRYPT, Tables.KEYS + "." + Keys.CAN_ENCRYPT);
|
||||||
@ -412,6 +413,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
|
projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
|
||||||
projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
|
projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
|
||||||
projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
|
projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
|
||||||
|
projectionMap.put(Keys.KEY_CURVE_OID, Keys.KEY_CURVE_OID);
|
||||||
projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
|
projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
|
||||||
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
|
||||||
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
|
||||||
|
@ -62,7 +62,6 @@ import org.sufficientlysecure.keychain.util.FileImportCache;
|
|||||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressFixedScaler;
|
import org.sufficientlysecure.keychain.util.ProgressFixedScaler;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -328,6 +327,7 @@ public class ProviderHelper {
|
|||||||
|
|
||||||
values.put(Keys.KEY_ID, key.getKeyId());
|
values.put(Keys.KEY_ID, key.getKeyId());
|
||||||
values.put(Keys.KEY_SIZE, key.getBitStrength());
|
values.put(Keys.KEY_SIZE, key.getBitStrength());
|
||||||
|
values.put(Keys.KEY_CURVE_OID, key.getCurveOid());
|
||||||
values.put(Keys.ALGORITHM, key.getAlgorithm());
|
values.put(Keys.ALGORITHM, key.getAlgorithm());
|
||||||
values.put(Keys.FINGERPRINT, key.getFingerprint());
|
values.put(Keys.FINGERPRINT, key.getFingerprint());
|
||||||
|
|
||||||
|
@ -347,9 +347,14 @@ public class OperationResultParcel implements Parcelable {
|
|||||||
MSG_CR_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
|
MSG_CR_ERROR_NO_CERTIFY (R.string.msg_cr_error_no_certify),
|
||||||
MSG_CR_ERROR_NULL_EXPIRY(R.string.msg_cr_error_null_expiry),
|
MSG_CR_ERROR_NULL_EXPIRY(R.string.msg_cr_error_null_expiry),
|
||||||
MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
|
MSG_CR_ERROR_KEYSIZE_512 (R.string.msg_cr_error_keysize_512),
|
||||||
|
MSG_CR_ERROR_NO_KEYSIZE (R.string.msg_cr_error_no_keysize),
|
||||||
|
MSG_CR_ERROR_NO_CURVE (R.string.msg_cr_error_no_curve),
|
||||||
MSG_CR_ERROR_UNKNOWN_ALGO (R.string.msg_cr_error_unknown_algo),
|
MSG_CR_ERROR_UNKNOWN_ALGO (R.string.msg_cr_error_unknown_algo),
|
||||||
MSG_CR_ERROR_INTERNAL_PGP (R.string.msg_cr_error_internal_pgp),
|
MSG_CR_ERROR_INTERNAL_PGP (R.string.msg_cr_error_internal_pgp),
|
||||||
MSG_CR_ERROR_MASTER_ELGAMAL (R.string.msg_cr_error_master_elgamal),
|
MSG_CR_ERROR_FLAGS_DSA (R.string.msg_cr_error_flags_dsa),
|
||||||
|
MSG_CR_ERROR_FLAGS_ELGAMAL (R.string.msg_cr_error_flags_elgamal),
|
||||||
|
MSG_CR_ERROR_FLAGS_ECDSA (R.string.msg_cr_error_flags_ecdsa),
|
||||||
|
MSG_CR_ERROR_FLAGS_ECDH (R.string.msg_cr_error_flags_ecdh),
|
||||||
|
|
||||||
// secret key modify
|
// secret key modify
|
||||||
MSG_MF (R.string.msg_mr),
|
MSG_MF (R.string.msg_mr),
|
||||||
|
@ -80,14 +80,16 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
// performance gain for using Parcelable here would probably be negligible,
|
// performance gain for using Parcelable here would probably be negligible,
|
||||||
// use Serializable instead.
|
// use Serializable instead.
|
||||||
public static class SubkeyAdd implements Serializable {
|
public static class SubkeyAdd implements Serializable {
|
||||||
public int mAlgorithm;
|
public Algorithm mAlgorithm;
|
||||||
public int mKeysize;
|
public Integer mKeySize;
|
||||||
|
public Curve mCurve;
|
||||||
public int mFlags;
|
public int mFlags;
|
||||||
public Long mExpiry;
|
public Long mExpiry;
|
||||||
|
|
||||||
public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
|
public SubkeyAdd(Algorithm algorithm, Integer keySize, Curve curve, int flags, Long expiry) {
|
||||||
mAlgorithm = algorithm;
|
mAlgorithm = algorithm;
|
||||||
mKeysize = keysize;
|
mKeySize = keySize;
|
||||||
|
mCurve = curve;
|
||||||
mFlags = flags;
|
mFlags = flags;
|
||||||
mExpiry = expiry;
|
mExpiry = expiry;
|
||||||
}
|
}
|
||||||
@ -95,7 +97,8 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String out = "mAlgorithm: " + mAlgorithm + ", ";
|
String out = "mAlgorithm: " + mAlgorithm + ", ";
|
||||||
out += "mKeysize: " + mKeysize + ", ";
|
out += "mKeySize: " + mKeySize + ", ";
|
||||||
|
out += "mCurve: " + mCurve + ", ";
|
||||||
out += "mFlags: " + mFlags;
|
out += "mFlags: " + mFlags;
|
||||||
out += "mExpiry: " + mExpiry;
|
out += "mExpiry: " + mExpiry;
|
||||||
|
|
||||||
@ -214,4 +217,20 @@ public class SaveKeyringParcel implements Parcelable {
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All supported algorithms
|
||||||
|
public enum Algorithm {
|
||||||
|
RSA, DSA, ELGAMAL, ECDSA, ECDH
|
||||||
|
}
|
||||||
|
|
||||||
|
// All curves defined in the standard
|
||||||
|
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269
|
||||||
|
public enum Curve {
|
||||||
|
NIST_P256, NIST_P384, NIST_P521,
|
||||||
|
|
||||||
|
// these are supported by gpg, but they are not in rfc6637 and not supported by BouncyCastle yet
|
||||||
|
// (adding support would be trivial though -> JcaPGPKeyConverter.java:190)
|
||||||
|
// BRAINPOOL_P256, BRAINPOOL_P384, BRAINPOOL_P512
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
|
|||||||
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
import org.sufficientlysecure.keychain.service.OperationResultParcel;
|
||||||
import org.sufficientlysecure.keychain.service.OperationResults;
|
import org.sufficientlysecure.keychain.service.OperationResults;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.Notify;
|
import org.sufficientlysecure.keychain.util.Notify;
|
||||||
|
|
||||||
@ -165,9 +166,12 @@ public class CreateKeyFinalFragment extends Fragment {
|
|||||||
Bundle data = new Bundle();
|
Bundle data = new Bundle();
|
||||||
|
|
||||||
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
SaveKeyringParcel parcel = new SaveKeyringParcel();
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.CERTIFY_OTHER, 0L));
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.RSA, 4096, null, KeyFlags.CERTIFY_OTHER, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(PublicKeyAlgorithmTags.RSA_GENERAL, 4096, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Algorithm.RSA, 4096, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Algorithm.RSA, 4096, null, KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, 0L));
|
||||||
String userId = KeyRing.createUserId(mName, mEmail, null);
|
String userId = KeyRing.createUserId(mName, mEmail, null);
|
||||||
parcel.mAddUserIds.add(userId);
|
parcel.mAddUserIds.add(userId);
|
||||||
parcel.mChangePrimaryUserId = userId;
|
parcel.mChangePrimaryUserId = userId;
|
||||||
|
@ -167,7 +167,7 @@ public class ViewCertActivity extends ActionBarActivity
|
|||||||
mStatus.setTextColor(getResources().getColor(R.color.black));
|
mStatus.setTextColor(getResources().getColor(R.color.black));
|
||||||
}
|
}
|
||||||
|
|
||||||
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(this, sig.getKeyAlgorithm(), 0);
|
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(this, sig.getKeyAlgorithm(), null, null);
|
||||||
mAlgorithm.setText(algorithmStr);
|
mAlgorithm.setText(algorithmStr);
|
||||||
|
|
||||||
mRowReason.setVisibility(View.GONE);
|
mRowReason.setVisibility(View.GONE);
|
||||||
|
@ -155,8 +155,8 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
|
|||||||
// don't show full fingerprint on key import
|
// don't show full fingerprint on key import
|
||||||
holder.fingerprint.setVisibility(View.GONE);
|
holder.fingerprint.setVisibility(View.GONE);
|
||||||
|
|
||||||
if (entry.getBitStrength() != 0 && entry.getAlgorithm() != null) {
|
if (entry.getAlgorithm() != null) {
|
||||||
holder.algorithm.setText("" + entry.getBitStrength() + "/" + entry.getAlgorithm());
|
holder.algorithm.setText(entry.getAlgorithm());
|
||||||
holder.algorithm.setVisibility(View.VISIBLE);
|
holder.algorithm.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
holder.algorithm.setVisibility(View.INVISIBLE);
|
holder.algorithm.setVisibility(View.INVISIBLE);
|
||||||
|
@ -52,6 +52,7 @@ public class SubkeysAdapter extends CursorAdapter {
|
|||||||
Keys.RANK,
|
Keys.RANK,
|
||||||
Keys.ALGORITHM,
|
Keys.ALGORITHM,
|
||||||
Keys.KEY_SIZE,
|
Keys.KEY_SIZE,
|
||||||
|
Keys.KEY_CURVE_OID,
|
||||||
Keys.HAS_SECRET,
|
Keys.HAS_SECRET,
|
||||||
Keys.CAN_CERTIFY,
|
Keys.CAN_CERTIFY,
|
||||||
Keys.CAN_ENCRYPT,
|
Keys.CAN_ENCRYPT,
|
||||||
@ -66,14 +67,15 @@ public class SubkeysAdapter extends CursorAdapter {
|
|||||||
private static final int INDEX_RANK = 2;
|
private static final int INDEX_RANK = 2;
|
||||||
private static final int INDEX_ALGORITHM = 3;
|
private static final int INDEX_ALGORITHM = 3;
|
||||||
private static final int INDEX_KEY_SIZE = 4;
|
private static final int INDEX_KEY_SIZE = 4;
|
||||||
private static final int INDEX_HAS_SECRET = 5;
|
private static final int INDEX_KEY_CURVE_OID = 5;
|
||||||
private static final int INDEX_CAN_CERTIFY = 6;
|
private static final int INDEX_HAS_SECRET = 6;
|
||||||
private static final int INDEX_CAN_ENCRYPT = 7;
|
private static final int INDEX_CAN_CERTIFY = 7;
|
||||||
private static final int INDEX_CAN_SIGN = 8;
|
private static final int INDEX_CAN_ENCRYPT = 8;
|
||||||
private static final int INDEX_IS_REVOKED = 9;
|
private static final int INDEX_CAN_SIGN = 9;
|
||||||
private static final int INDEX_CREATION = 10;
|
private static final int INDEX_IS_REVOKED = 10;
|
||||||
private static final int INDEX_EXPIRY = 11;
|
private static final int INDEX_CREATION = 11;
|
||||||
private static final int INDEX_FINGERPRINT = 12;
|
private static final int INDEX_EXPIRY = 12;
|
||||||
|
private static final int INDEX_FINGERPRINT = 13;
|
||||||
|
|
||||||
public SubkeysAdapter(Context context, Cursor c, int flags,
|
public SubkeysAdapter(Context context, Cursor c, int flags,
|
||||||
SaveKeyringParcel saveKeyringParcel) {
|
SaveKeyringParcel saveKeyringParcel) {
|
||||||
@ -141,7 +143,8 @@ public class SubkeysAdapter extends CursorAdapter {
|
|||||||
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
||||||
context,
|
context,
|
||||||
cursor.getInt(INDEX_ALGORITHM),
|
cursor.getInt(INDEX_ALGORITHM),
|
||||||
cursor.getInt(INDEX_KEY_SIZE)
|
cursor.getInt(INDEX_KEY_SIZE),
|
||||||
|
cursor.getString(INDEX_KEY_CURVE_OID)
|
||||||
);
|
);
|
||||||
|
|
||||||
vKeyId.setText(keyIdStr);
|
vKeyId.setText(keyIdStr);
|
||||||
|
@ -42,14 +42,10 @@ public class SubkeysAddedAdapter extends ArrayAdapter<SaveKeyringParcel.SubkeyAd
|
|||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
|
|
||||||
// hold a private reference to the underlying data List
|
|
||||||
private List<SaveKeyringParcel.SubkeyAdd> mData;
|
|
||||||
|
|
||||||
public SubkeysAddedAdapter(Activity activity, List<SaveKeyringParcel.SubkeyAdd> data) {
|
public SubkeysAddedAdapter(Activity activity, List<SaveKeyringParcel.SubkeyAdd> data) {
|
||||||
super(activity, -1, data);
|
super(activity, -1, data);
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
mData = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ViewHolder {
|
static class ViewHolder {
|
||||||
@ -103,7 +99,8 @@ public class SubkeysAddedAdapter extends ArrayAdapter<SaveKeyringParcel.SubkeyAd
|
|||||||
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
|
||||||
mActivity,
|
mActivity,
|
||||||
holder.mModel.mAlgorithm,
|
holder.mModel.mAlgorithm,
|
||||||
holder.mModel.mKeysize
|
holder.mModel.mKeySize,
|
||||||
|
holder.mModel.mCurve
|
||||||
);
|
);
|
||||||
holder.vKeyId.setText(R.string.edit_key_new_subkey);
|
holder.vKeyId.setText(R.string.edit_key_new_subkey);
|
||||||
holder.vKeyDetails.setText(algorithmStr);
|
holder.vKeyDetails.setText(algorithmStr);
|
||||||
|
@ -20,14 +20,12 @@ package org.sufficientlysecure.keychain.ui.dialog;
|
|||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.format.DateUtils;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
@ -43,16 +41,16 @@ import android.widget.TableRow;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.PublicKeyAlgorithmTags;
|
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
|
||||||
import org.sufficientlysecure.keychain.util.Choice;
|
import org.sufficientlysecure.keychain.util.Choice;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
public class AddSubkeyDialogFragment extends DialogFragment {
|
public class AddSubkeyDialogFragment extends DialogFragment {
|
||||||
@ -69,7 +67,10 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
private TableRow mExpiryRow;
|
private TableRow mExpiryRow;
|
||||||
private DatePicker mExpiryDatePicker;
|
private DatePicker mExpiryDatePicker;
|
||||||
private Spinner mAlgorithmSpinner;
|
private Spinner mAlgorithmSpinner;
|
||||||
|
private View mKeySizeRow;
|
||||||
private Spinner mKeySizeSpinner;
|
private Spinner mKeySizeSpinner;
|
||||||
|
private View mCurveRow;
|
||||||
|
private Spinner mCurveSpinner;
|
||||||
private TextView mCustomKeyTextView;
|
private TextView mCustomKeyTextView;
|
||||||
private EditText mCustomKeyEditText;
|
private EditText mCustomKeyEditText;
|
||||||
private TextView mCustomKeyInfoTextView;
|
private TextView mCustomKeyInfoTextView;
|
||||||
@ -114,6 +115,9 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mExpiryDatePicker = (DatePicker) view.findViewById(R.id.add_subkey_expiry_date_picker);
|
mExpiryDatePicker = (DatePicker) view.findViewById(R.id.add_subkey_expiry_date_picker);
|
||||||
mAlgorithmSpinner = (Spinner) view.findViewById(R.id.add_subkey_algorithm);
|
mAlgorithmSpinner = (Spinner) view.findViewById(R.id.add_subkey_algorithm);
|
||||||
mKeySizeSpinner = (Spinner) view.findViewById(R.id.add_subkey_size);
|
mKeySizeSpinner = (Spinner) view.findViewById(R.id.add_subkey_size);
|
||||||
|
mCurveSpinner = (Spinner) view.findViewById(R.id.add_subkey_curve);
|
||||||
|
mKeySizeRow = view.findViewById(R.id.add_subkey_row_size);
|
||||||
|
mCurveRow = view.findViewById(R.id.add_subkey_row_curve);
|
||||||
mCustomKeyTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_label);
|
mCustomKeyTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_label);
|
||||||
mCustomKeyEditText = (EditText) view.findViewById(R.id.add_subkey_custom_key_size_input);
|
mCustomKeyEditText = (EditText) view.findViewById(R.id.add_subkey_custom_key_size_input);
|
||||||
mCustomKeyInfoTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_info);
|
mCustomKeyInfoTextView = (TextView) view.findViewById(R.id.add_subkey_custom_key_size_info);
|
||||||
@ -140,30 +144,32 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
|
mExpiryDatePicker.setMinDate(minDateCal.getTime().getTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<Choice> choices = new ArrayList<Choice>();
|
{
|
||||||
choices.add(new Choice(PublicKeyAlgorithmTags.DSA, getResources().getString(
|
ArrayList<Choice<Algorithm>> choices = new ArrayList<Choice<Algorithm>>();
|
||||||
|
choices.add(new Choice<Algorithm>(Algorithm.DSA, getResources().getString(
|
||||||
R.string.dsa)));
|
R.string.dsa)));
|
||||||
if (!mWillBeMasterKey) {
|
if (!mWillBeMasterKey) {
|
||||||
choices.add(new Choice(PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, getResources().getString(
|
choices.add(new Choice<Algorithm>(Algorithm.ELGAMAL, getResources().getString(
|
||||||
R.string.elgamal)));
|
R.string.elgamal)));
|
||||||
}
|
}
|
||||||
choices.add(new Choice(PublicKeyAlgorithmTags.RSA_GENERAL, getResources().getString(
|
choices.add(new Choice<Algorithm>(Algorithm.RSA, getResources().getString(
|
||||||
R.string.rsa)));
|
R.string.rsa)));
|
||||||
choices.add(new Choice(PublicKeyAlgorithmTags.ECDH, getResources().getString(
|
choices.add(new Choice<Algorithm>(Algorithm.ECDSA, getResources().getString(
|
||||||
R.string.ecdh)));
|
|
||||||
choices.add(new Choice(PublicKeyAlgorithmTags.ECDSA, getResources().getString(
|
|
||||||
R.string.ecdsa)));
|
R.string.ecdsa)));
|
||||||
ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context,
|
choices.add(new Choice<Algorithm>(Algorithm.ECDH, getResources().getString(
|
||||||
|
R.string.ecdh)));
|
||||||
|
ArrayAdapter<Choice<Algorithm>> adapter = new ArrayAdapter<Choice<Algorithm>>(context,
|
||||||
android.R.layout.simple_spinner_item, choices);
|
android.R.layout.simple_spinner_item, choices);
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
mAlgorithmSpinner.setAdapter(adapter);
|
mAlgorithmSpinner.setAdapter(adapter);
|
||||||
// make RSA the default
|
// make RSA the default
|
||||||
for (int i = 0; i < choices.size(); ++i) {
|
for (int i = 0; i < choices.size(); ++i) {
|
||||||
if (choices.get(i).getId() == PublicKeyAlgorithmTags.RSA_GENERAL) {
|
if (choices.get(i).getId() == Algorithm.RSA) {
|
||||||
mAlgorithmSpinner.setSelection(i);
|
mAlgorithmSpinner.setSelection(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change
|
// dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change
|
||||||
ArrayAdapter<CharSequence> keySizeAdapter = new ArrayAdapter<CharSequence>(context, android.R.layout.simple_spinner_item,
|
ArrayAdapter<CharSequence> keySizeAdapter = new ArrayAdapter<CharSequence>(context, android.R.layout.simple_spinner_item,
|
||||||
@ -172,6 +178,36 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mKeySizeSpinner.setAdapter(keySizeAdapter);
|
mKeySizeSpinner.setAdapter(keySizeAdapter);
|
||||||
mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length
|
mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length
|
||||||
|
|
||||||
|
{
|
||||||
|
ArrayList<Choice<Curve>> choices = new ArrayList<Choice<Curve>>();
|
||||||
|
|
||||||
|
choices.add(new Choice<Curve>(Curve.NIST_P256, getResources().getString(
|
||||||
|
R.string.key_curve_nist_p256)));
|
||||||
|
choices.add(new Choice<Curve>(Curve.NIST_P384, getResources().getString(
|
||||||
|
R.string.key_curve_nist_p384)));
|
||||||
|
choices.add(new Choice<Curve>(Curve.NIST_P521, getResources().getString(
|
||||||
|
R.string.key_curve_nist_p521)));
|
||||||
|
|
||||||
|
/* @see SaveKeyringParcel
|
||||||
|
choices.add(new Choice<Curve>(Curve.BRAINPOOL_P256, getResources().getString(
|
||||||
|
R.string.key_curve_bp_p256)));
|
||||||
|
choices.add(new Choice<Curve>(Curve.BRAINPOOL_P384, getResources().getString(
|
||||||
|
R.string.key_curve_bp_p384)));
|
||||||
|
choices.add(new Choice<Curve>(Curve.BRAINPOOL_P512, getResources().getString(
|
||||||
|
R.string.key_curve_bp_p512)));
|
||||||
|
*/
|
||||||
|
|
||||||
|
ArrayAdapter<Choice<Curve>> adapter = new ArrayAdapter<Choice<Curve>>(context,
|
||||||
|
android.R.layout.simple_spinner_item, choices);
|
||||||
|
mCurveSpinner.setAdapter(adapter);
|
||||||
|
// make NIST P-256 the default
|
||||||
|
for (int i = 0; i < choices.size(); ++i) {
|
||||||
|
if (choices.get(i).getId() == Curve.NIST_P256) {
|
||||||
|
mCurveSpinner.setSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dialog.setCancelable(true);
|
dialog.setCancelable(true);
|
||||||
|
|
||||||
@ -211,7 +247,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
updateUiForAlgorithm(((Choice) parent.getSelectedItem()).getId());
|
updateUiForAlgorithm(((Choice<Algorithm>) parent.getSelectedItem()).getId());
|
||||||
|
|
||||||
setCustomKeyVisibility();
|
setCustomKeyVisibility();
|
||||||
setOkButtonAvailability(alertDialog);
|
setOkButtonAvailability(alertDialog);
|
||||||
@ -241,11 +277,16 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dismiss only if at least one flag is selected
|
Algorithm algorithm = ((Choice<Algorithm>) mAlgorithmSpinner.getSelectedItem()).getId();
|
||||||
dismiss();
|
Curve curve = null;
|
||||||
|
Integer keySize = null;
|
||||||
Choice newKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
|
// For EC keys, add a curve
|
||||||
int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), getSelectedKeyLength());
|
if (algorithm == Algorithm.ECDH || algorithm == Algorithm.ECDSA) {
|
||||||
|
curve = ((Choice<Curve>) mCurveSpinner.getSelectedItem()).getId();
|
||||||
|
// Otherwise, get a keysize
|
||||||
|
} else {
|
||||||
|
keySize = getProperKeyLength(algorithm, getSelectedKeyLength());
|
||||||
|
}
|
||||||
|
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (mFlagCertify.isChecked()) {
|
if (mFlagCertify.isChecked()) {
|
||||||
@ -276,12 +317,12 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
|
SaveKeyringParcel.SubkeyAdd newSubkey = new SaveKeyringParcel.SubkeyAdd(
|
||||||
newKeyAlgorithmChoice.getId(),
|
algorithm, keySize, curve, flags, expiry
|
||||||
newKeySize,
|
|
||||||
flags,
|
|
||||||
expiry
|
|
||||||
);
|
);
|
||||||
mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
|
mAlgorithmSelectedListener.onAlgorithmSelected(newSubkey);
|
||||||
|
|
||||||
|
// finally, dismiss the dialogue
|
||||||
|
dismiss();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
negativeButton.setOnClickListener(new View.OnClickListener() {
|
negativeButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@ -323,16 +364,16 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
* @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is
|
* @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is
|
||||||
* inappropriate.
|
* inappropriate.
|
||||||
*/
|
*/
|
||||||
private int getProperKeyLength(int algorithmId, int currentKeyLength) {
|
private int getProperKeyLength(Algorithm algorithm, int currentKeyLength) {
|
||||||
final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192};
|
final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192};
|
||||||
int properKeyLength = -1;
|
int properKeyLength = -1;
|
||||||
switch (algorithmId) {
|
switch (algorithm) {
|
||||||
case PublicKeyAlgorithmTags.RSA_GENERAL:
|
case RSA:
|
||||||
if (currentKeyLength > 1024 && currentKeyLength <= 16384) {
|
if (currentKeyLength > 1024 && currentKeyLength <= 16384) {
|
||||||
properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8);
|
properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
|
case ELGAMAL:
|
||||||
int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length];
|
int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length];
|
||||||
for (int i = 0; i < elGamalSupportedLengths.length; i++) {
|
for (int i = 0; i < elGamalSupportedLengths.length; i++) {
|
||||||
elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength);
|
elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength);
|
||||||
@ -347,7 +388,7 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
properKeyLength = elGamalSupportedLengths[minimalIndex];
|
properKeyLength = elGamalSupportedLengths[minimalIndex];
|
||||||
break;
|
break;
|
||||||
case PublicKeyAlgorithmTags.DSA:
|
case DSA:
|
||||||
if (currentKeyLength >= 512 && currentKeyLength <= 1024) {
|
if (currentKeyLength >= 512 && currentKeyLength <= 1024) {
|
||||||
properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64);
|
properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64);
|
||||||
}
|
}
|
||||||
@ -357,10 +398,10 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setOkButtonAvailability(AlertDialog alertDialog) {
|
private void setOkButtonAvailability(AlertDialog alertDialog) {
|
||||||
final Choice selectedAlgorithm = (Choice) mAlgorithmSpinner.getSelectedItem();
|
Algorithm algorithm = ((Choice<Algorithm>) mAlgorithmSpinner.getSelectedItem()).getId();
|
||||||
final int selectedKeySize = getSelectedKeyLength(); //Integer.parseInt((String) mKeySizeSpinner.getSelectedItem());
|
boolean enabled = algorithm == Algorithm.ECDSA || algorithm == Algorithm.ECDH
|
||||||
final int properKeyLength = getProperKeyLength(selectedAlgorithm.getId(), selectedKeySize);
|
|| getProperKeyLength(algorithm, getSelectedKeyLength()) > 0;
|
||||||
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(properKeyLength > 0);
|
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setCustomKeyVisibility() {
|
private void setCustomKeyVisibility() {
|
||||||
@ -376,18 +417,20 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
// hide keyboard after setting visibility to gone
|
// hide keyboard after setting visibility to gone
|
||||||
if (visibility == View.GONE) {
|
if (visibility == View.GONE) {
|
||||||
InputMethodManager imm = (InputMethodManager)
|
InputMethodManager imm = (InputMethodManager)
|
||||||
getActivity().getSystemService(getActivity().INPUT_METHOD_SERVICE);
|
getActivity().getSystemService(FragmentActivity.INPUT_METHOD_SERVICE);
|
||||||
imm.hideSoftInputFromWindow(mCustomKeyEditText.getWindowToken(), 0);
|
imm.hideSoftInputFromWindow(mCustomKeyEditText.getWindowToken(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUiForAlgorithm(int algorithmId) {
|
private void updateUiForAlgorithm(Algorithm algorithm) {
|
||||||
final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) mKeySizeSpinner.getAdapter();
|
final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) mKeySizeSpinner.getAdapter();
|
||||||
final Object selectedItem = mKeySizeSpinner.getSelectedItem();
|
|
||||||
keySizeAdapter.clear();
|
keySizeAdapter.clear();
|
||||||
switch (algorithmId) {
|
switch (algorithm) {
|
||||||
case PublicKeyAlgorithmTags.RSA_GENERAL:
|
case RSA:
|
||||||
replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
|
replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
|
||||||
|
mKeySizeSpinner.setSelection(1);
|
||||||
|
mKeySizeRow.setVisibility(View.VISIBLE);
|
||||||
|
mCurveRow.setVisibility(View.GONE);
|
||||||
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_rsa));
|
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_rsa));
|
||||||
// allowed flags:
|
// allowed flags:
|
||||||
mFlagSign.setEnabled(true);
|
mFlagSign.setEnabled(true);
|
||||||
@ -409,8 +452,11 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
mFlagAuthenticate.setChecked(false);
|
mFlagAuthenticate.setChecked(false);
|
||||||
break;
|
break;
|
||||||
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
|
case ELGAMAL:
|
||||||
replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
|
replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
|
||||||
|
mKeySizeSpinner.setSelection(3);
|
||||||
|
mKeySizeRow.setVisibility(View.VISIBLE);
|
||||||
|
mCurveRow.setVisibility(View.GONE);
|
||||||
mCustomKeyInfoTextView.setText(""); // ElGamal does not support custom key length
|
mCustomKeyInfoTextView.setText(""); // ElGamal does not support custom key length
|
||||||
// allowed flags:
|
// allowed flags:
|
||||||
mFlagCertify.setChecked(false);
|
mFlagCertify.setChecked(false);
|
||||||
@ -422,8 +468,11 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mFlagAuthenticate.setChecked(false);
|
mFlagAuthenticate.setChecked(false);
|
||||||
mFlagAuthenticate.setEnabled(false);
|
mFlagAuthenticate.setEnabled(false);
|
||||||
break;
|
break;
|
||||||
case PublicKeyAlgorithmTags.DSA:
|
case DSA:
|
||||||
replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
|
replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
|
||||||
|
mKeySizeSpinner.setSelection(2);
|
||||||
|
mKeySizeRow.setVisibility(View.VISIBLE);
|
||||||
|
mCurveRow.setVisibility(View.GONE);
|
||||||
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_dsa));
|
mCustomKeyInfoTextView.setText(getResources().getString(R.string.key_size_custom_info_dsa));
|
||||||
// allowed flags:
|
// allowed flags:
|
||||||
mFlagCertify.setChecked(false);
|
mFlagCertify.setChecked(false);
|
||||||
@ -435,16 +484,37 @@ public class AddSubkeyDialogFragment extends DialogFragment {
|
|||||||
mFlagAuthenticate.setChecked(false);
|
mFlagAuthenticate.setChecked(false);
|
||||||
mFlagAuthenticate.setEnabled(false);
|
mFlagAuthenticate.setEnabled(false);
|
||||||
break;
|
break;
|
||||||
|
case ECDSA:
|
||||||
|
mKeySizeRow.setVisibility(View.GONE);
|
||||||
|
mCurveRow.setVisibility(View.VISIBLE);
|
||||||
|
mCustomKeyInfoTextView.setText("");
|
||||||
|
// allowed flags:
|
||||||
|
mFlagCertify.setEnabled(mWillBeMasterKey);
|
||||||
|
mFlagCertify.setChecked(mWillBeMasterKey);
|
||||||
|
mFlagSign.setEnabled(true);
|
||||||
|
mFlagSign.setChecked(!mWillBeMasterKey);
|
||||||
|
mFlagEncrypt.setEnabled(false);
|
||||||
|
mFlagEncrypt.setChecked(false);
|
||||||
|
mFlagAuthenticate.setEnabled(true);
|
||||||
|
mFlagAuthenticate.setChecked(false);
|
||||||
|
break;
|
||||||
|
case ECDH:
|
||||||
|
mKeySizeRow.setVisibility(View.GONE);
|
||||||
|
mCurveRow.setVisibility(View.VISIBLE);
|
||||||
|
mCustomKeyInfoTextView.setText("");
|
||||||
|
// allowed flags:
|
||||||
|
mFlagCertify.setChecked(false);
|
||||||
|
mFlagCertify.setEnabled(false);
|
||||||
|
mFlagSign.setChecked(false);
|
||||||
|
mFlagSign.setEnabled(false);
|
||||||
|
mFlagEncrypt.setChecked(true);
|
||||||
|
mFlagEncrypt.setEnabled(true);
|
||||||
|
mFlagAuthenticate.setChecked(false);
|
||||||
|
mFlagAuthenticate.setEnabled(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
keySizeAdapter.notifyDataSetChanged();
|
keySizeAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
// when switching algorithm, try to select same key length as before
|
|
||||||
for (int i = 0; i < keySizeAdapter.getCount(); i++) {
|
|
||||||
if (selectedItem.equals(keySizeAdapter.getItem(i))) {
|
|
||||||
mKeySizeSpinner.setSelection(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
@ -17,21 +17,16 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.util;
|
package org.sufficientlysecure.keychain.util;
|
||||||
|
|
||||||
public class Choice {
|
public class Choice <E> {
|
||||||
private String mName;
|
private String mName;
|
||||||
private int mId;
|
private E mId;
|
||||||
|
|
||||||
public Choice() {
|
public Choice(E id, String name) {
|
||||||
mId = -1;
|
|
||||||
mName = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Choice(int id, String name) {
|
|
||||||
mId = id;
|
mId = id;
|
||||||
mName = name;
|
mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public E getId() {
|
||||||
return mId;
|
return mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
android:padding="4dp" />
|
android:padding="4dp" />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow>
|
<TableRow android:id="@+id/add_subkey_row_size">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -50,6 +50,24 @@
|
|||||||
android:padding="4dp" />
|
android:padding="4dp" />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow
|
||||||
|
android:id="@+id/add_subkey_row_curve"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:text="@string/label_ecc_curve"/>
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/add_subkey_curve"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right"
|
||||||
|
android:padding="4dp"/>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/add_subkey_custom_key_size_label"
|
android:id="@+id/add_subkey_custom_key_size_label"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -109,6 +109,7 @@
|
|||||||
<string name="label_expiry">Expiry</string>
|
<string name="label_expiry">Expiry</string>
|
||||||
<string name="label_usage">Usage</string>
|
<string name="label_usage">Usage</string>
|
||||||
<string name="label_key_size">Key Size</string>
|
<string name="label_key_size">Key Size</string>
|
||||||
|
<string name="label_ecc_curve">Elliptic Curve</string>
|
||||||
<string name="label_main_user_id">Primary identity</string>
|
<string name="label_main_user_id">Primary identity</string>
|
||||||
<string name="label_name">Name</string>
|
<string name="label_name">Name</string>
|
||||||
<string name="label_comment">Comment</string>
|
<string name="label_comment">Comment</string>
|
||||||
@ -270,6 +271,8 @@
|
|||||||
<string name="progress_generating_rsa">generating new RSA key…</string>
|
<string name="progress_generating_rsa">generating new RSA key…</string>
|
||||||
<string name="progress_generating_dsa">generating new DSA key…</string>
|
<string name="progress_generating_dsa">generating new DSA key…</string>
|
||||||
<string name="progress_generating_elgamal">generating new ElGamal key…</string>
|
<string name="progress_generating_elgamal">generating new ElGamal key…</string>
|
||||||
|
<string name="progress_generating_ecdsa">generating new ECDSA key…</string>
|
||||||
|
<string name="progress_generating_ecdh">generating new ECDH key…</string>
|
||||||
|
|
||||||
<string name="progress_modify">modifying keyring…</string>
|
<string name="progress_modify">modifying keyring…</string>
|
||||||
|
|
||||||
@ -326,6 +329,16 @@
|
|||||||
<string name="key_size_custom_info_rsa">RSA key length must be greater than 1024 and at most 16384. Also it must be multiplicity of 8.</string>
|
<string name="key_size_custom_info_rsa">RSA key length must be greater than 1024 and at most 16384. Also it must be multiplicity of 8.</string>
|
||||||
<string name="key_size_custom_info_dsa">DSA key length must be at least 512 and at most 1024. Also it must be multiplicity of 64.</string>
|
<string name="key_size_custom_info_dsa">DSA key length must be at least 512 and at most 1024. Also it must be multiplicity of 64.</string>
|
||||||
|
|
||||||
|
<!-- elliptic curve names -->
|
||||||
|
<string name="key_curve_nist_p256">NIST P-256</string>
|
||||||
|
<string name="key_curve_nist_p384">NIST P-384</string>
|
||||||
|
<string name="key_curve_nist_p521">NIST P-521</string>
|
||||||
|
<!-- not in for now, see SaveKeyringParcel
|
||||||
|
<string name="key_curve_bp_p256">Brainpool P-256</string>
|
||||||
|
<string name="key_curve_bp_p384">Brainpool P-384</string>
|
||||||
|
<string name="key_curve_bp_p512">Brainpool P-512</string>
|
||||||
|
-->
|
||||||
|
|
||||||
<!-- compression -->
|
<!-- compression -->
|
||||||
<string name="compression_fast">fast</string>
|
<string name="compression_fast">fast</string>
|
||||||
<string name="compression_very_slow">very slow</string>
|
<string name="compression_very_slow">very slow</string>
|
||||||
@ -636,9 +649,14 @@
|
|||||||
<string name="msg_cr_error_no_certify">Master key must have certify flag!</string>
|
<string name="msg_cr_error_no_certify">Master key must have certify flag!</string>
|
||||||
<string name="msg_cr_error_null_expiry">Expiry time cannot be "same as before" on key creation. This is a programming error, please file a bug report!</string>
|
<string name="msg_cr_error_null_expiry">Expiry time cannot be "same as before" on key creation. This is a programming error, please file a bug report!</string>
|
||||||
<string name="msg_cr_error_keysize_512">Key size must be greater or equal 512!</string>
|
<string name="msg_cr_error_keysize_512">Key size must be greater or equal 512!</string>
|
||||||
|
<string name="msg_cr_error_no_curve">No key size specified! This is a programming error, please file a bug report!</string>
|
||||||
|
<string name="msg_cr_error_no_keysize">No elliptic curve specified! This is a programming error, please file a bug report!</string>
|
||||||
<string name="msg_cr_error_internal_pgp">Internal PGP error!</string>
|
<string name="msg_cr_error_internal_pgp">Internal PGP error!</string>
|
||||||
<string name="msg_cr_error_unknown_algo">Bad algorithm choice!</string>
|
<string name="msg_cr_error_unknown_algo">Unknown algorithm selected! This is a programming error, please file a bug report!</string>
|
||||||
<string name="msg_cr_error_master_elgamal">Master key must not be of type ElGamal!</string>
|
<string name="msg_cr_error_flags_dsa">Bad key flags selected, DSA cannot be used for encryption!</string>
|
||||||
|
<string name="msg_cr_error_flags_elgamal">Bad key flags selected, ElGamal cannot be used for signing!</string>
|
||||||
|
<string name="msg_cr_error_flags_ecdsa">Bad key flags selected, ECDSA cannot be used for encryption!</string>
|
||||||
|
<string name="msg_cr_error_flags_ecdh">Bad key flags selected, ECDH cannot be used for signing!</string>
|
||||||
|
|
||||||
<!-- modifySecretKeyRing -->
|
<!-- modifySecretKeyRing -->
|
||||||
<string name="msg_mr">Modifying keyring %s</string>
|
<string name="msg_mr">Modifying keyring %s</string>
|
||||||
@ -663,7 +681,7 @@
|
|||||||
<string name="msg_mf_primary_new">Generating new certificate for new primary user id</string>
|
<string name="msg_mf_primary_new">Generating new certificate for new primary user id</string>
|
||||||
<string name="msg_mf_subkey_change">Modifying subkey %s</string>
|
<string name="msg_mf_subkey_change">Modifying subkey %s</string>
|
||||||
<string name="msg_mf_error_subkey_missing">Tried to operate on missing subkey %s!</string>
|
<string name="msg_mf_error_subkey_missing">Tried to operate on missing subkey %s!</string>
|
||||||
<string name="msg_mf_subkey_new">Adding new subkey of type %2$s (%1$s bit)</string>
|
<string name="msg_mf_subkey_new">Adding new subkey of type %s</string>
|
||||||
<string name="msg_mf_subkey_new_id">New subkey ID: %s</string>
|
<string name="msg_mf_subkey_new_id">New subkey ID: %s</string>
|
||||||
<string name="msg_mf_error_past_expiry">Expiry date cannot be in the past!</string>
|
<string name="msg_mf_error_past_expiry">Expiry date cannot be in the past!</string>
|
||||||
<string name="msg_mf_subkey_revoke">Revoking subkey %s</string>
|
<string name="msg_mf_subkey_revoke">Revoking subkey %s</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user