From 340e0289ef677bec7b7d5df2d414e361dd687519 Mon Sep 17 00:00:00 2001 From: Dominik Date: Wed, 25 Apr 2012 17:28:35 +0200 Subject: reworking createKey --- org_apg/src/org/thialfihar/android/apg/Apg.java | 109 ++++++++++++++------- org_apg/src/org/thialfihar/android/apg/Id.java | 33 +++++-- .../thialfihar/android/apg/service/ApgService.java | 8 +- .../thialfihar/android/apg/ui/EditKeyActivity.java | 34 +++---- .../android/apg/ui/widget/SectionView.java | 19 +++- .../src/org/thialfihar/android/apg/util/Utils.java | 18 +++- 6 files changed, 151 insertions(+), 70 deletions(-) (limited to 'org_apg/src') diff --git a/org_apg/src/org/thialfihar/android/apg/Apg.java b/org_apg/src/org/thialfihar/android/apg/Apg.java index 9d8264dd4..d702f6883 100644 --- a/org_apg/src/org/thialfihar/android/apg/Apg.java +++ b/org_apg/src/org/thialfihar/android/apg/Apg.java @@ -53,6 +53,16 @@ import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.PGPV3SignatureGenerator; +import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.PGPDigestCalculator; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; +import org.thialfihar.android.apg.Id.return_value; import org.thialfihar.android.apg.KeyServer.AddKeyException; import org.thialfihar.android.apg.provider.DataProvider; import org.thialfihar.android.apg.provider.Database; @@ -94,6 +104,7 @@ import java.io.OutputStream; import java.io.RandomAccessFile; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; @@ -111,6 +122,12 @@ import java.util.Vector; import java.util.regex.Pattern; public class Apg { + + static { + // register spongy castle provider + Security.addProvider(new BouncyCastleProvider()); + } + public static final String PACKAGE_NAME = "org.thialfihar.android.apg"; private static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent."; @@ -296,8 +313,26 @@ public class Apg { return delay; } - public static PGPSecretKey createKey(Context context, int algorithmChoice, int keySize, - String passPhrase, PGPSecretKey masterKey) throws NoSuchAlgorithmException, + /** + * Creates new secret key. The returned PGPSecretKeyRing contains only one newly generated key + * when this key is the new masterkey. If a masterkey is supplied in the parameters + * PGPSecretKeyRing contains the masterkey and the new key as a subkey (certified by the + * masterkey). + * + * @param context + * @param algorithmChoice + * @param keySize + * @param passPhrase + * @param masterSecretKey + * @return + * @throws NoSuchAlgorithmException + * @throws PGPException + * @throws NoSuchProviderException + * @throws GeneralException + * @throws InvalidAlgorithmParameterException + */ + public static PGPSecretKeyRing createKey(Context context, int algorithmChoice, int keySize, + String passPhrase, PGPSecretKey masterSecretKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, GeneralException, InvalidAlgorithmParameterException { @@ -305,8 +340,6 @@ public class Apg { throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit)); } - Security.addProvider(new BouncyCastleProvider()); - if (passPhrase == null) { passPhrase = ""; } @@ -316,18 +349,18 @@ public class Apg { switch (algorithmChoice) { case Id.choice.algorithm.dsa: { - keyGen = KeyPairGenerator.getInstance("DSA", new BouncyCastleProvider()); + keyGen = KeyPairGenerator.getInstance("DSA", "SC"); keyGen.initialize(keySize, new SecureRandom()); algorithm = PGPPublicKey.DSA; break; } case Id.choice.algorithm.elgamal: { - if (masterKey == null) { + if (masterSecretKey == null) { throw new GeneralException( context.getString(R.string.error_masterKeyMustNotBeElGamal)); } - keyGen = KeyPairGenerator.getInstance("ELGAMAL", new BouncyCastleProvider()); + keyGen = KeyPairGenerator.getInstance("ELGAMAL", "SC"); BigInteger p = Primes.getBestPrime(keySize); BigInteger g = new BigInteger("2"); @@ -339,7 +372,7 @@ public class Apg { } case Id.choice.algorithm.rsa: { - keyGen = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider()); + keyGen = KeyPairGenerator.getInstance("RSA", "SC"); keyGen.initialize(keySize, new SecureRandom()); algorithm = PGPPublicKey.RSA_GENERAL; @@ -351,38 +384,45 @@ public class Apg { } } - PGPKeyPair keyPair = new PGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); + // build new key pair + PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - PGPSecretKey secretKey = null; - if (masterKey == null) { - // enough for now, as we assemble the key again later anyway - secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "", - PGPEncryptedData.CAST5, passPhrase.toCharArray(), null, null, - new SecureRandom(), new BouncyCastleProvider().getName()); + // define hashing and signing algos + PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get( + HashAlgorithmTags.SHA1); + PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair + .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); - } else { - PGPPublicKey tmpKey = masterKey.getPublicKey(); - PGPPublicKey masterPublicKey = new PGPPublicKey(tmpKey.getAlgorithm(), - tmpKey.getKey(new BouncyCastleProvider()), tmpKey.getCreationTime()); - PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(passPhrase.toCharArray(), - new BouncyCastleProvider()); + // Build key encrypter and decrypter based on passphrase + PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( + PGPEncryptedData.CAST5, sha1Calc).setProvider("SC").build(passPhrase.toCharArray()); + PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() + .setProvider("SC").build(passPhrase.toCharArray()); + + PGPSecretKeyRing secKeyRing = null; + if (masterSecretKey == null) { + // build keyRing with only this one master key in it! + PGPKeyRingGenerator ringGen = new PGPKeyRingGenerator( + PGPSignature.DEFAULT_CERTIFICATION, keyPair, "", sha1Calc, null, null, + certificationSignerBuilder, keyEncryptor); + + secKeyRing = ringGen.generateSecretKeyRing(); + } else { + PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); + PGPPrivateKey masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); + + // build keyRing with master key and new key as subkey (certified by masterkey) PGPKeyRingGenerator ringGen = new PGPKeyRingGenerator( - PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, "", PGPEncryptedData.CAST5, - passPhrase.toCharArray(), null, null, new SecureRandom(), - new BouncyCastleProvider().getName()); + PGPSignature.DEFAULT_CERTIFICATION, masterKeyPair, "", sha1Calc, null, null, + certificationSignerBuilder, keyEncryptor); + ringGen.addSubKey(keyPair); - PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing(); - Iterator it = secKeyRing.getSecretKeys(); - // first one is the master key - it.next(); - secretKey = it.next(); + secKeyRing = ringGen.generateSecretKeyRing(); } - Log.d(Constants.TAG, "new secretkey: " + secretKey.toString()); - - return secretKey; + return secKeyRing; } public static void buildSecretKey(Context context, ArrayList userIds, @@ -394,8 +434,6 @@ public class Apg { if (progress != null) progress.setProgress(R.string.progress_buildingKey, 0, 100); - Security.addProvider(new BouncyCastleProvider()); - if (oldPassPhrase == null || oldPassPhrase.equals("")) { oldPassPhrase = ""; } @@ -1239,7 +1277,6 @@ public class Apg { int hashAlgorithm, int compression, boolean forceV3Signature, String passPhrase) throws IOException, GeneralException, PGPException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException { - Security.addProvider(new BouncyCastleProvider()); if (encryptionKeyIds == null) { encryptionKeyIds = new long[0]; @@ -1394,7 +1431,6 @@ public class Apg { long signatureKeyId, String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException, PGPException, IOException, NoSuchAlgorithmException, SignatureException { - Security.addProvider(new BouncyCastleProvider()); ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream); armorOut.setHeader("Version", getFullVersion(context)); @@ -1500,7 +1536,6 @@ public class Apg { int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException, PGPException, IOException, NoSuchAlgorithmException, SignatureException { - Security.addProvider(new BouncyCastleProvider()); ArmoredOutputStream armorOut = null; OutputStream out = null; diff --git a/org_apg/src/org/thialfihar/android/apg/Id.java b/org_apg/src/org/thialfihar/android/apg/Id.java index 138a9535d..d4d23b80e 100644 --- a/org_apg/src/org/thialfihar/android/apg/Id.java +++ b/org_apg/src/org/thialfihar/android/apg/Id.java @@ -83,18 +83,31 @@ public final class Id { // public static final int query_done = 0x21070010; // public static final int unknown_signature_key = 0x21070011; // } - + + // use only lower 16 bits due to compatibility lib public static final class request { - public static final int public_keys = 0x21070001; - public static final int secret_keys = 0x21070002; - public static final int filename = 0x21070003; - public static final int output_filename = 0x21070004; - public static final int key_server_preference = 0x21070005; - public static final int look_up_key_id = 0x21070006; - public static final int export_to_server = 0x21070007; - public static final int import_from_qr_code = 0x21070008; - public static final int sign_key = 0x21070009; + public static final int public_keys = 0x00007001; + public static final int secret_keys = 0x00007002; + public static final int filename = 0x00007003; + public static final int output_filename = 0x00007004; + public static final int key_server_preference = 0x00007005; + public static final int look_up_key_id = 0x00007006; + public static final int export_to_server = 0x00007007; + public static final int import_from_qr_code = 0x00007008; + public static final int sign_key = 0x00007009; } + +// public static final class request { +// public static final int public_keys = 0x21070001; +// public static final int secret_keys = 0x21070002; +// public static final int filename = 0x21070003; +// public static final int output_filename = 0x21070004; +// public static final int key_server_preference = 0x21070005; +// public static final int look_up_key_id = 0x21070006; +// public static final int export_to_server = 0x21070007; +// public static final int import_from_qr_code = 0x21070008; +// public static final int sign_key = 0x21070009; +// } public static final class dialog { public static final int pass_phrase = 0x21070001; diff --git a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java index 6a27ba45d..b7b2b24bc 100644 --- a/org_apg/src/org/thialfihar/android/apg/service/ApgService.java +++ b/org_apg/src/org/thialfihar/android/apg/service/ApgService.java @@ -19,6 +19,7 @@ package org.thialfihar.android.apg.service; import java.util.ArrayList; import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.ProgressDialogUpdater; @@ -147,12 +148,13 @@ public class ApgService extends IntentService implements ProgressDialogUpdater { } // Operation - PGPSecretKey newKey = Apg - .createKey(this, algorithm, keysize, passphrase, masterKey); + PGPSecretKeyRing newKeyRing = Apg.createKey(this, algorithm, keysize, passphrase, + masterKey); // Output Bundle resultData = new Bundle(); - resultData.putByteArray(ApgHandler.NEW_KEY, Utils.PGPSecretKeyToBytes(newKey)); + resultData.putByteArray(ApgHandler.NEW_KEY, + Utils.PGPSecretKeyRingToBytes(newKeyRing)); sendMessageToHandler(ApgHandler.MESSAGE_OKAY, null, resultData); } catch (Exception e) { sendErrorToHandler(e); diff --git a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java index 339d743b6..dc102ce12 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/EditKeyActivity.java @@ -169,23 +169,23 @@ public class EditKeyActivity extends SherlockFragmentActivity { // extends BaseA .getBoolean(Apg.EXTRA_GENERATE_DEFAULT_KEYS); if (generateDefaultKeys) { - // generate a RSA 2048 key for encryption and signing! - try { - PGPSecretKey masterKey = Apg.createKey(this, Id.choice.algorithm.rsa, - 2048, mCurrentPassPhrase, null); - - // add new masterKey to keys array, which is then added to view - keys.add(masterKey); - keysUsages.add(Id.choice.usage.sign_only); - - PGPSecretKey subKey = Apg.createKey(this, Id.choice.algorithm.rsa, - 2048, mCurrentPassPhrase, masterKey); - - keys.add(subKey); - keysUsages.add(Id.choice.usage.encrypt_only); - } catch (Exception e) { - Log.e(Constants.TAG, "Creating initial key failed: +" + e); - } +// // generate a RSA 2048 key for encryption and signing! +// try { +// PGPSecretKey masterKey = Apg.createKey(this, Id.choice.algorithm.rsa, +// 2048, mCurrentPassPhrase, null); +// +// // add new masterKey to keys array, which is then added to view +// keys.add(masterKey); +// keysUsages.add(Id.choice.usage.sign_only); +// +// PGPSecretKey subKey = Apg.createKey(this, Id.choice.algorithm.rsa, +// 2048, mCurrentPassPhrase, masterKey); +// +// keys.add(subKey); +// keysUsages.add(Id.choice.usage.encrypt_only); +// } catch (Exception e) { +// Log.e(Constants.TAG, "Creating initial key failed: +" + e); +// } } } diff --git a/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java b/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java index 895e2b5a6..7efdf0b3d 100644 --- a/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java +++ b/org_apg/src/org/thialfihar/android/apg/ui/widget/SectionView.java @@ -17,6 +17,7 @@ package org.thialfihar.android.apg.ui.widget; import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.service.ApgHandler; @@ -48,6 +49,7 @@ import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; +import java.util.Iterator; import java.util.Vector; public class SectionView extends LinearLayout implements OnClickListener, EditorListener { @@ -282,14 +284,27 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (message.arg1 == ApgHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service Bundle data = message.getData(); - PGPSecretKey newKey = Utils.BytesToPGPSecretKey(data + PGPSecretKeyRing newKeyRing = Utils.BytesToPGPSecretKeyRing(data .getByteArray(ApgHandler.NEW_KEY)); + boolean isMasterKey = (mEditors.getChildCount() == 0); + + // take only the key from this ring + PGPSecretKey newKey = null; + Iterator it = newKeyRing.getSecretKeys(); + + if (isMasterKey) { + newKey = it.next(); + } else { + // first one is the master key + it.next(); + newKey = it.next(); + } + // add view with new key KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false); view.setEditorListener(SectionView.this); - boolean isMasterKey = (mEditors.getChildCount() == 0); view.setValue(newKey, isMasterKey, -1); mEditors.addView(view); SectionView.this.updateEditorsVisible(); diff --git a/org_apg/src/org/thialfihar/android/apg/util/Utils.java b/org_apg/src/org/thialfihar/android/apg/util/Utils.java index 13bfb7b91..394d95954 100644 --- a/org_apg/src/org/thialfihar/android/apg/util/Utils.java +++ b/org_apg/src/org/thialfihar/android/apg/util/Utils.java @@ -110,7 +110,7 @@ public class Utils { * @param keysBytes * @return */ - public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) { + public static PGPSecretKeyRing BytesToPGPSecretKeyRing(byte[] keysBytes) { PGPObjectFactory factory = new PGPObjectFactory(keysBytes); PGPSecretKeyRing keyRing = null; try { @@ -120,6 +120,12 @@ public class Utils { } catch (IOException e) { e.printStackTrace(); } + + return keyRing; + } + + public static ArrayList BytesToPGPSecretKeyList(byte[] keysBytes) { + PGPSecretKeyRing keyRing = BytesToPGPSecretKeyRing(keysBytes); ArrayList keys = new ArrayList(); Iterator itr = keyRing.getSecretKeys(); @@ -146,4 +152,14 @@ public class Utils { } } + public static byte[] PGPSecretKeyRingToBytes(PGPSecretKeyRing keyRing) { + try { + return keyRing.getEncoded(); + } catch (IOException e) { + Log.e(Constants.TAG, "Encoding failed: ", e); + + return null; + } + } + } -- cgit v1.2.3