reworking createKey

This commit is contained in:
Dominik
2012-04-25 17:28:35 +02:00
parent f06fcd989b
commit 340e0289ef
6 changed files with 152 additions and 71 deletions

View File

@@ -53,6 +53,16 @@ import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector; import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.PGPV3SignatureGenerator; 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.KeyServer.AddKeyException;
import org.thialfihar.android.apg.provider.DataProvider; import org.thialfihar.android.apg.provider.DataProvider;
import org.thialfihar.android.apg.provider.Database; import org.thialfihar.android.apg.provider.Database;
@@ -94,6 +104,7 @@ import java.io.OutputStream;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
@@ -111,6 +122,12 @@ import java.util.Vector;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class Apg { public class Apg {
static {
// register spongy castle provider
Security.addProvider(new BouncyCastleProvider());
}
public static final String PACKAGE_NAME = "org.thialfihar.android.apg"; public static final String PACKAGE_NAME = "org.thialfihar.android.apg";
private static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent."; private static final String INTENT_PREFIX = "org.thialfihar.android.apg.intent.";
@@ -296,8 +313,26 @@ public class Apg {
return delay; 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, PGPException, NoSuchProviderException, GeneralException,
InvalidAlgorithmParameterException { InvalidAlgorithmParameterException {
@@ -305,8 +340,6 @@ public class Apg {
throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit)); throw new GeneralException(context.getString(R.string.error_keySizeMinimum512bit));
} }
Security.addProvider(new BouncyCastleProvider());
if (passPhrase == null) { if (passPhrase == null) {
passPhrase = ""; passPhrase = "";
} }
@@ -316,18 +349,18 @@ public class Apg {
switch (algorithmChoice) { switch (algorithmChoice) {
case Id.choice.algorithm.dsa: { case Id.choice.algorithm.dsa: {
keyGen = KeyPairGenerator.getInstance("DSA", new BouncyCastleProvider()); keyGen = KeyPairGenerator.getInstance("DSA", "SC");
keyGen.initialize(keySize, new SecureRandom()); keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.DSA; algorithm = PGPPublicKey.DSA;
break; break;
} }
case Id.choice.algorithm.elgamal: { case Id.choice.algorithm.elgamal: {
if (masterKey == null) { if (masterSecretKey == null) {
throw new GeneralException( throw new GeneralException(
context.getString(R.string.error_masterKeyMustNotBeElGamal)); context.getString(R.string.error_masterKeyMustNotBeElGamal));
} }
keyGen = KeyPairGenerator.getInstance("ELGAMAL", new BouncyCastleProvider()); keyGen = KeyPairGenerator.getInstance("ELGAMAL", "SC");
BigInteger p = Primes.getBestPrime(keySize); BigInteger p = Primes.getBestPrime(keySize);
BigInteger g = new BigInteger("2"); BigInteger g = new BigInteger("2");
@@ -339,7 +372,7 @@ public class Apg {
} }
case Id.choice.algorithm.rsa: { case Id.choice.algorithm.rsa: {
keyGen = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider()); keyGen = KeyPairGenerator.getInstance("RSA", "SC");
keyGen.initialize(keySize, new SecureRandom()); keyGen.initialize(keySize, new SecureRandom());
algorithm = PGPPublicKey.RSA_GENERAL; 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; // define hashing and signing algos
if (masterKey == null) { PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(
// enough for now, as we assemble the key again later anyway HashAlgorithmTags.SHA1);
secretKey = new PGPSecretKey(PGPSignature.DEFAULT_CERTIFICATION, keyPair, "", PGPContentSignerBuilder certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair
PGPEncryptedData.CAST5, passPhrase.toCharArray(), null, null, .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1);
new SecureRandom(), new BouncyCastleProvider().getName());
} else { // Build key encrypter and decrypter based on passphrase
PGPPublicKey tmpKey = masterKey.getPublicKey(); PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
PGPPublicKey masterPublicKey = new PGPPublicKey(tmpKey.getAlgorithm(), PGPEncryptedData.CAST5, sha1Calc).setProvider("SC").build(passPhrase.toCharArray());
tmpKey.getKey(new BouncyCastleProvider()), tmpKey.getCreationTime()); PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
PGPPrivateKey masterPrivateKey = masterKey.extractPrivateKey(passPhrase.toCharArray(), .setProvider("SC").build(passPhrase.toCharArray());
new BouncyCastleProvider());
PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); PGPSecretKeyRing secKeyRing = null;
if (masterSecretKey == null) {
// build keyRing with only this one master key in it!
PGPKeyRingGenerator ringGen = new PGPKeyRingGenerator( PGPKeyRingGenerator ringGen = new PGPKeyRingGenerator(
PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, "", PGPEncryptedData.CAST5, PGPSignature.DEFAULT_CERTIFICATION, keyPair, "", sha1Calc, null, null,
passPhrase.toCharArray(), null, null, new SecureRandom(), certificationSignerBuilder, keyEncryptor);
new BouncyCastleProvider().getName());
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.DEFAULT_CERTIFICATION, masterKeyPair, "", sha1Calc, null, null,
certificationSignerBuilder, keyEncryptor);
ringGen.addSubKey(keyPair); ringGen.addSubKey(keyPair);
PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing(); secKeyRing = ringGen.generateSecretKeyRing();
Iterator<PGPSecretKey> it = secKeyRing.getSecretKeys();
// first one is the master key
it.next();
secretKey = it.next();
} }
Log.d(Constants.TAG, "new secretkey: " + secretKey.toString()); return secKeyRing;
return secretKey;
} }
public static void buildSecretKey(Context context, ArrayList<String> userIds, public static void buildSecretKey(Context context, ArrayList<String> userIds,
@@ -394,8 +434,6 @@ public class Apg {
if (progress != null) if (progress != null)
progress.setProgress(R.string.progress_buildingKey, 0, 100); progress.setProgress(R.string.progress_buildingKey, 0, 100);
Security.addProvider(new BouncyCastleProvider());
if (oldPassPhrase == null || oldPassPhrase.equals("")) { if (oldPassPhrase == null || oldPassPhrase.equals("")) {
oldPassPhrase = ""; oldPassPhrase = "";
} }
@@ -1239,7 +1277,6 @@ public class Apg {
int hashAlgorithm, int compression, boolean forceV3Signature, String passPhrase) int hashAlgorithm, int compression, boolean forceV3Signature, String passPhrase)
throws IOException, GeneralException, PGPException, NoSuchProviderException, throws IOException, GeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException { NoSuchAlgorithmException, SignatureException {
Security.addProvider(new BouncyCastleProvider());
if (encryptionKeyIds == null) { if (encryptionKeyIds == null) {
encryptionKeyIds = new long[0]; encryptionKeyIds = new long[0];
@@ -1394,7 +1431,6 @@ public class Apg {
long signatureKeyId, String signaturePassPhrase, int hashAlgorithm, long signatureKeyId, String signaturePassPhrase, int hashAlgorithm,
boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException, boolean forceV3Signature, ProgressDialogUpdater progress) throws GeneralException,
PGPException, IOException, NoSuchAlgorithmException, SignatureException { PGPException, IOException, NoSuchAlgorithmException, SignatureException {
Security.addProvider(new BouncyCastleProvider());
ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream); ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", getFullVersion(context)); armorOut.setHeader("Version", getFullVersion(context));
@@ -1500,7 +1536,6 @@ public class Apg {
int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress) int hashAlgorithm, boolean forceV3Signature, ProgressDialogUpdater progress)
throws GeneralException, PGPException, IOException, NoSuchAlgorithmException, throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException { SignatureException {
Security.addProvider(new BouncyCastleProvider());
ArmoredOutputStream armorOut = null; ArmoredOutputStream armorOut = null;
OutputStream out = null; OutputStream out = null;

View File

@@ -84,18 +84,31 @@ public final class Id {
// public static final int unknown_signature_key = 0x21070011; // 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 class request {
public static final int public_keys = 0x21070001; public static final int public_keys = 0x00007001;
public static final int secret_keys = 0x21070002; public static final int secret_keys = 0x00007002;
public static final int filename = 0x21070003; public static final int filename = 0x00007003;
public static final int output_filename = 0x21070004; public static final int output_filename = 0x00007004;
public static final int key_server_preference = 0x21070005; public static final int key_server_preference = 0x00007005;
public static final int look_up_key_id = 0x21070006; public static final int look_up_key_id = 0x00007006;
public static final int export_to_server = 0x21070007; public static final int export_to_server = 0x00007007;
public static final int import_from_qr_code = 0x21070008; public static final int import_from_qr_code = 0x00007008;
public static final int sign_key = 0x21070009; 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 class dialog {
public static final int pass_phrase = 0x21070001; public static final int pass_phrase = 0x21070001;
public static final int encrypting = 0x21070002; public static final int encrypting = 0x21070002;

View File

@@ -19,6 +19,7 @@ package org.thialfihar.android.apg.service;
import java.util.ArrayList; import java.util.ArrayList;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Constants; import org.thialfihar.android.apg.Constants;
import org.thialfihar.android.apg.ProgressDialogUpdater; import org.thialfihar.android.apg.ProgressDialogUpdater;
@@ -147,12 +148,13 @@ public class ApgService extends IntentService implements ProgressDialogUpdater {
} }
// Operation // Operation
PGPSecretKey newKey = Apg PGPSecretKeyRing newKeyRing = Apg.createKey(this, algorithm, keysize, passphrase,
.createKey(this, algorithm, keysize, passphrase, masterKey); masterKey);
// Output // Output
Bundle resultData = new Bundle(); 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); sendMessageToHandler(ApgHandler.MESSAGE_OKAY, null, resultData);
} catch (Exception e) { } catch (Exception e) {
sendErrorToHandler(e); sendErrorToHandler(e);

View File

@@ -169,23 +169,23 @@ public class EditKeyActivity extends SherlockFragmentActivity { // extends BaseA
.getBoolean(Apg.EXTRA_GENERATE_DEFAULT_KEYS); .getBoolean(Apg.EXTRA_GENERATE_DEFAULT_KEYS);
if (generateDefaultKeys) { if (generateDefaultKeys) {
// generate a RSA 2048 key for encryption and signing! // // generate a RSA 2048 key for encryption and signing!
try { // try {
PGPSecretKey masterKey = Apg.createKey(this, Id.choice.algorithm.rsa, // PGPSecretKey masterKey = Apg.createKey(this, Id.choice.algorithm.rsa,
2048, mCurrentPassPhrase, null); // 2048, mCurrentPassPhrase, null);
//
// add new masterKey to keys array, which is then added to view // // add new masterKey to keys array, which is then added to view
keys.add(masterKey); // keys.add(masterKey);
keysUsages.add(Id.choice.usage.sign_only); // keysUsages.add(Id.choice.usage.sign_only);
//
PGPSecretKey subKey = Apg.createKey(this, Id.choice.algorithm.rsa, // PGPSecretKey subKey = Apg.createKey(this, Id.choice.algorithm.rsa,
2048, mCurrentPassPhrase, masterKey); // 2048, mCurrentPassPhrase, masterKey);
//
keys.add(subKey); // keys.add(subKey);
keysUsages.add(Id.choice.usage.encrypt_only); // keysUsages.add(Id.choice.usage.encrypt_only);
} catch (Exception e) { // } catch (Exception e) {
Log.e(Constants.TAG, "Creating initial key failed: +" + e); // Log.e(Constants.TAG, "Creating initial key failed: +" + e);
} // }
} }
} }

View File

@@ -17,6 +17,7 @@
package org.thialfihar.android.apg.ui.widget; package org.thialfihar.android.apg.ui.widget;
import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.thialfihar.android.apg.Apg; import org.thialfihar.android.apg.Apg;
import org.thialfihar.android.apg.Id; import org.thialfihar.android.apg.Id;
import org.thialfihar.android.apg.service.ApgHandler; import org.thialfihar.android.apg.service.ApgHandler;
@@ -48,6 +49,7 @@ import android.widget.LinearLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import java.util.Iterator;
import java.util.Vector; import java.util.Vector;
public class SectionView extends LinearLayout implements OnClickListener, EditorListener { 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) { if (message.arg1 == ApgHandler.MESSAGE_OKAY) {
// get new key from data bundle returned from service // get new key from data bundle returned from service
Bundle data = message.getData(); Bundle data = message.getData();
PGPSecretKey newKey = Utils.BytesToPGPSecretKey(data PGPSecretKeyRing newKeyRing = Utils.BytesToPGPSecretKeyRing(data
.getByteArray(ApgHandler.NEW_KEY)); .getByteArray(ApgHandler.NEW_KEY));
boolean isMasterKey = (mEditors.getChildCount() == 0);
// take only the key from this ring
PGPSecretKey newKey = null;
Iterator<PGPSecretKey> 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 // add view with new key
KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item,
mEditors, false); mEditors, false);
view.setEditorListener(SectionView.this); view.setEditorListener(SectionView.this);
boolean isMasterKey = (mEditors.getChildCount() == 0);
view.setValue(newKey, isMasterKey, -1); view.setValue(newKey, isMasterKey, -1);
mEditors.addView(view); mEditors.addView(view);
SectionView.this.updateEditorsVisible(); SectionView.this.updateEditorsVisible();

View File

@@ -110,7 +110,7 @@ public class Utils {
* @param keysBytes * @param keysBytes
* @return * @return
*/ */
public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) { public static PGPSecretKeyRing BytesToPGPSecretKeyRing(byte[] keysBytes) {
PGPObjectFactory factory = new PGPObjectFactory(keysBytes); PGPObjectFactory factory = new PGPObjectFactory(keysBytes);
PGPSecretKeyRing keyRing = null; PGPSecretKeyRing keyRing = null;
try { try {
@@ -120,6 +120,12 @@ public class Utils {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return keyRing;
}
public static ArrayList<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
PGPSecretKeyRing keyRing = BytesToPGPSecretKeyRing(keysBytes);
ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>(); ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>();
Iterator<PGPSecretKey> itr = keyRing.getSecretKeys(); Iterator<PGPSecretKey> 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;
}
}
} }