diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java index e406a142e..20d446824 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpConversionHelper.java @@ -80,9 +80,27 @@ public class PgpConversionHelper { * @return */ public static PGPSecretKey BytesToPGPSecretKey(byte[] keyBytes) { - PGPSecretKey key = BytesToPGPSecretKeyList(keyBytes).get(0); + PGPObjectFactory factory = new PGPObjectFactory(keyBytes); + Object obj = null; + try { + obj = factory.nextObject(); + } catch (IOException e) { + Log.e(Constants.TAG, "Error while converting to PGPSecretKey!", e); + } + PGPSecretKey secKey = null; + if(obj instanceof PGPSecretKey) { + if ((secKey = (PGPSecretKey)obj ) == null) { + Log.e(Constants.TAG, "No keys given!"); + } + } else if(obj instanceof PGPSecretKeyRing) { //master keys are sent as keyrings + PGPSecretKeyRing keyRing = null; + if ((keyRing = (PGPSecretKeyRing)obj) == null) { + Log.e(Constants.TAG, "No keys given!"); + } + secKey = keyRing.getSecretKey(); + } - return key; + return secKey; } /** diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index d6f130682..9782d1ac2 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -103,15 +103,12 @@ public class PgpKeyOperation { } /** - * 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). + * Creates new secret key. * * @param algorithmChoice * @param keySize * @param passPhrase - * @param masterSecretKey + * @param isMasterKey * @return * @throws NoSuchAlgorithmException * @throws PGPException @@ -119,9 +116,11 @@ public class PgpKeyOperation { * @throws PgpGeneralException * @throws InvalidAlgorithmParameterException */ - public PGPSecretKeyRing createKey(int algorithmChoice, int keySize, String passPhrase, - PGPSecretKey masterSecretKey) throws NoSuchAlgorithmException, PGPException, - NoSuchProviderException, PgpGeneralException, InvalidAlgorithmParameterException { + + // TODO: key flags? + public PGPSecretKey createKey(int algorithmChoice, int keySize, String passPhrase, + boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, + PgpGeneralException, InvalidAlgorithmParameterException { if (keySize < 512) { throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); @@ -143,7 +142,7 @@ public class PgpKeyOperation { } case Id.choice.algorithm.elgamal: { - if (masterSecretKey == null) { + if (isMasterKey) { throw new PgpGeneralException( mContext.getString(R.string.error_master_key_must_not_be_el_gamal)); } @@ -183,36 +182,11 @@ public class PgpKeyOperation { PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( PGPEncryptedData.CAST5, sha1Calc) .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); - PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( - Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); - PGPKeyRingGenerator ringGen = null; - PGPContentSignerBuilder certificationSignerBuilder = null; - if (masterSecretKey == null) { - certificationSignerBuilder = new JcaPGPContentSignerBuilder(keyPair.getPublicKey() - .getAlgorithm(), HashAlgorithmTags.SHA1); + PGPSecretKey secKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), + sha1Calc, isMasterKey, keyEncryptor); - // build keyRing with only this one master key in it! - ringGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, keyPair, "", - sha1Calc, null, null, certificationSignerBuilder, keyEncryptor); - } else { - PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); - PGPPrivateKey masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); - PGPKeyPair masterKeyPair = new PGPKeyPair(masterPublicKey, masterPrivateKey); - - certificationSignerBuilder = new JcaPGPContentSignerBuilder(masterKeyPair - .getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA1); - - // build keyRing with master key and new key as subkey (certified by masterkey) - ringGen = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, masterKeyPair, - "", sha1Calc, null, null, certificationSignerBuilder, keyEncryptor); - - ringGen.addSubKey(keyPair); - } - - PGPSecretKeyRing secKeyRing = ringGen.generateSecretKeyRing(); - - return secKeyRing; + return secKey; } public void changeSecretKeyPassphrase(PGPSecretKeyRing keyRing, String oldPassPhrase, diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index b23efb909..87a50af2e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -561,21 +561,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial int algorithm = data.getInt(GENERATE_KEY_ALGORITHM); String passphrase = data.getString(GENERATE_KEY_SYMMETRIC_PASSPHRASE); int keysize = data.getInt(GENERATE_KEY_KEY_SIZE); - PGPSecretKey masterKey = null; - if (data.containsKey(GENERATE_KEY_MASTER_KEY)) { - masterKey = PgpConversionHelper.BytesToPGPSecretKey(data - .getByteArray(GENERATE_KEY_MASTER_KEY)); - } + boolean masterKey = data.getBoolean(GENERATE_KEY_MASTER_KEY); /* Operation */ PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); - PGPSecretKeyRing newKeyRing = keyOperations.createKey(algorithm, keysize, + PGPSecretKey newKey = keyOperations.createKey(algorithm, keysize, passphrase, masterKey); /* Output */ Bundle resultData = new Bundle(); resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyRingToBytes(newKeyRing)); + PgpConversionHelper.PGPSecretKeyToBytes(newKey)); OtherHelper.logDebugBundle(resultData, "resultData"); @@ -592,18 +588,21 @@ public class KeychainIntentService extends IntentService implements ProgressDial /* Operation */ PgpKeyOperation keyOperations = new PgpKeyOperation(this, this); - PGPSecretKeyRing masterKeyRing = keyOperations.createKey(Id.choice.algorithm.rsa, - 4096, passphrase, null); + PGPSecretKey masterKey = keyOperations.createKey(Id.choice.algorithm.rsa, + 4096, passphrase, true); - PGPSecretKeyRing subKeyRing = keyOperations.createKey(Id.choice.algorithm.rsa, - 4096, passphrase, masterKeyRing.getSecretKey()); + PGPSecretKey subKey = keyOperations.createKey(Id.choice.algorithm.rsa, + 4096, passphrase, false); + + // TODO: default to one master for cert, one sub for encrypt and one sub + // for sign /* Output */ Bundle resultData = new Bundle(); resultData.putByteArray(RESULT_NEW_KEY, - PgpConversionHelper.PGPSecretKeyRingToBytes(masterKeyRing)); + PgpConversionHelper.PGPSecretKeyToBytes(masterKey)); resultData.putByteArray(RESULT_NEW_KEY2, - PgpConversionHelper.PGPSecretKeyRingToBytes(subKeyRing)); + PgpConversionHelper.PGPSecretKeyToBytes(subKey)); OtherHelper.logDebugBundle(resultData, "resultData"); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index cf11ffa48..09334fe6d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -193,25 +193,20 @@ public class EditKeyActivity extends SherlockFragmentActivity { if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service Bundle data = message.getData(); - PGPSecretKeyRing masterKeyRing = (PGPSecretKeyRing) PgpConversionHelper - .BytesToPGPKeyRing(data + PGPSecretKey masterKey = (PGPSecretKey) PgpConversionHelper + .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); - PGPSecretKeyRing subKeyRing = (PGPSecretKeyRing) PgpConversionHelper - .BytesToPGPKeyRing(data + PGPSecretKey subKey = (PGPSecretKey) PgpConversionHelper + .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY2)); // add master key - @SuppressWarnings("unchecked") - Iterator masterIt = masterKeyRing.getSecretKeys(); - mKeys.add(masterIt.next()); - mKeysUsages.add(Id.choice.usage.sign_only); + mKeys.add(masterKey); + mKeysUsages.add(Id.choice.usage.sign_only); //TODO: get from key flags // add sub key - @SuppressWarnings("unchecked") - Iterator subIt = subKeyRing.getSecretKeys(); - subIt.next(); // masterkey - mKeys.add(subIt.next()); - mKeysUsages.add(Id.choice.usage.encrypt_only); + mKeys.add(subKey); + mKeysUsages.add(Id.choice.usage.encrypt_only); //TODO: get from key flags buildLayout(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 3175d79a4..277f75c1a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -290,18 +290,19 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor // fill values for this action Bundle data = new Bundle(); + Boolean isMasterKey; String passPhrase; if (mEditors.getChildCount() > 0) { PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); passPhrase = PassphraseCacheService .getCachedPassphrase(mActivity, masterKey.getKeyID()); - - data.putByteArray(KeychainIntentService.GENERATE_KEY_MASTER_KEY, - PgpConversionHelper.PGPSecretKeyToBytes(masterKey)); + isMasterKey = false; } else { passPhrase = ""; + isMasterKey = true; } + data.putBoolean(KeychainIntentService.GENERATE_KEY_MASTER_KEY, isMasterKey); data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase); data.putInt(KeychainIntentService.GENERATE_KEY_ALGORITHM, mNewKeyAlgorithmChoice.getId()); data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize); @@ -322,11 +323,10 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { // get new key from data bundle returned from service Bundle data = message.getData(); - PGPSecretKeyRing newKeyRing = (PGPSecretKeyRing) PgpConversionHelper - .BytesToPGPKeyRing(data + PGPSecretKey newKey = (PGPSecretKey) PgpConversionHelper + .BytesToPGPSecretKey(data .getByteArray(KeychainIntentService.RESULT_NEW_KEY)); - - addGeneratedKeyToView(newKeyRing); + addGeneratedKeyToView(newKey); } }; }; @@ -341,27 +341,12 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor mActivity.startService(intent); } - private void addGeneratedKeyToView(PGPSecretKeyRing newKeyRing) { - boolean isMasterKey = (mEditors.getChildCount() == 0); - - // take only the key from this ring - PGPSecretKey newKey = null; - @SuppressWarnings("unchecked") - Iterator it = newKeyRing.getSecretKeys(); - - if (isMasterKey) { - newKey = it.next(); - } else { - // first one is the master key - it.next(); - newKey = it.next(); - } - + private void addGeneratedKeyToView(PGPSecretKey newKey) { // add view with new key KeyEditor view = (KeyEditor) mInflater.inflate(R.layout.edit_key_key_item, mEditors, false); view.setEditorListener(SectionView.this); - view.setValue(newKey, isMasterKey, -1); + view.setValue(newKey, newKey.isMasterKey(), -1); mEditors.addView(view); SectionView.this.updateEditorsVisible(); } diff --git a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPObjectFactory.java b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPObjectFactory.java index 11fb3a53c..73b11b9a1 100644 --- a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPObjectFactory.java +++ b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPObjectFactory.java @@ -103,6 +103,15 @@ public class PGPObjectFactory { throw new IOException("can't create secret key object: " + e); } + case PacketTags.SECRET_SUBKEY: + try + { + return PGPSecretKeyRing.readSubkey(in, fingerPrintCalculator); + } + catch (PGPException e) + { + throw new IOException("processing error: " + e.getMessage()); + } case PacketTags.PUBLIC_KEY: return new PGPPublicKeyRing(in, fingerPrintCalculator); case PacketTags.PUBLIC_SUBKEY: diff --git a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKey.java b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKey.java index d705e5ce6..c0f7dfa3b 100644 --- a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKey.java +++ b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKey.java @@ -64,7 +64,7 @@ public class PGPSecretKey this(privKey, pubKey, checksumCalculator, false, keyEncryptor); } - PGPSecretKey( + public PGPSecretKey( PGPPrivateKey privKey, PGPPublicKey pubKey, PGPDigestCalculator checksumCalculator, diff --git a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKeyRing.java b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKeyRing.java index c182a1f1e..6df4c0c91 100644 --- a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKeyRing.java +++ b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/PGPSecretKeyRing.java @@ -477,4 +477,23 @@ public class PGPSecretKeyRing return new PGPSecretKeyRing(keys, secRing.extraPubKeys); } + + public static PGPSecretKey readSubkey(BCPGInputStream in, KeyFingerPrintCalculator fingerPrintCalculator) + throws IOException, PGPException + { + SecretSubkeyPacket sub = (SecretSubkeyPacket)in.readPacket(); + + // + // ignore GPG comment packets if found. + // + while (in.nextPacketTag() == PacketTags.EXPERIMENTAL_2) + { + in.readPacket(); + } + + TrustPacket subTrust = readOptionalTrustPacket(in); + List sigList = readSignaturesAndTrust(in); + + return new PGPSecretKey(sub, new PGPPublicKey(sub.getPublicKeyPacket(), subTrust, sigList, fingerPrintCalculator)); + } }