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.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());
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(
PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, "", PGPEncryptedData.CAST5,
passPhrase.toCharArray(), null, null, new SecureRandom(),
new BouncyCastleProvider().getName());
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.DEFAULT_CERTIFICATION, masterKeyPair, "", sha1Calc, null, null,
certificationSignerBuilder, keyEncryptor);
ringGen.addSubKey(keyPair);
PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing();
Iterator<PGPSecretKey> 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<String> 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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
// }
}
}

View File

@ -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<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
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();

View File

@ -110,7 +110,7 @@ public class Utils {
* @param keysBytes
* @return
*/
public static ArrayList<PGPSecretKey> 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<PGPSecretKey> BytesToPGPSecretKeyList(byte[] keysBytes) {
PGPSecretKeyRing keyRing = BytesToPGPSecretKeyRing(keysBytes);
ArrayList<PGPSecretKey> keys = new ArrayList<PGPSecretKey>();
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;
}
}
}