mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-11 11:35:07 -05:00
reworking createKey
This commit is contained in:
parent
f06fcd989b
commit
340e0289ef
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user