support yubikeys in (some) edit key operations
This commit is contained in:
@@ -149,10 +149,14 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
|
||||
}
|
||||
|
||||
public boolean unlock(String passphrase) throws PgpGeneralException {
|
||||
return unlock(passphrase.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true on right passphrase
|
||||
*/
|
||||
public boolean unlock(String passphrase) throws PgpGeneralException {
|
||||
public boolean unlock(char[] passphrase) throws PgpGeneralException {
|
||||
// handle keys on OpenPGP cards like they were unlocked
|
||||
if (mSecretKey.getS2K() != null
|
||||
&& mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K
|
||||
@@ -164,7 +168,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
|
||||
// try to extract keys using the passphrase
|
||||
try {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
||||
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
|
||||
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
|
||||
} catch (PGPException e) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
package org.sufficientlysecure.keychain.pgp;
|
||||
|
||||
import org.spongycastle.bcpg.HashAlgorithmTags;
|
||||
import org.spongycastle.bcpg.S2K;
|
||||
import org.spongycastle.bcpg.sig.Features;
|
||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||
import org.spongycastle.jce.spec.ElGamalParameterSpec;
|
||||
@@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.PGPDataDecryptor;
|
||||
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
|
||||
@@ -43,6 +44,8 @@ import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBu
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder;
|
||||
import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
@@ -54,6 +57,9 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Curve;
|
||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.IterableIterator;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
@@ -85,9 +91,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* This indicator may be null.
|
||||
*/
|
||||
public class PgpKeyOperation {
|
||||
|
||||
private Stack<Progressable> mProgress;
|
||||
private AtomicBoolean mCancelled;
|
||||
|
||||
NfcSignOperationsBuilder mNfcSignOps;
|
||||
private CryptoInputParcel mCryptoInput;
|
||||
|
||||
public PgpKeyOperation(Progressable progress) {
|
||||
super();
|
||||
if (progress != null) {
|
||||
@@ -96,9 +106,11 @@ public class PgpKeyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled) {
|
||||
public PgpKeyOperation(Progressable progress, AtomicBoolean cancelled, CryptoInputParcel cryptoInput) {
|
||||
this(progress);
|
||||
mCancelled = cancelled;
|
||||
mNfcSignOps = new NfcSignOperationsBuilder(cryptoInput.getSignatureTime());
|
||||
mCryptoInput = cryptoInput;
|
||||
}
|
||||
|
||||
private boolean checkCancelled() {
|
||||
@@ -316,7 +328,8 @@ public class PgpKeyOperation {
|
||||
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
|
||||
|
||||
subProgressPush(50, 100);
|
||||
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log);
|
||||
CryptoInputParcel cryptoInput = new CryptoInputParcel(new Date(), "");
|
||||
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, log);
|
||||
|
||||
} catch (PGPException e) {
|
||||
log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
|
||||
@@ -347,8 +360,8 @@ public class PgpKeyOperation {
|
||||
* namely stripping of subkeys and changing the protection mode of dummy keys.
|
||||
*
|
||||
*/
|
||||
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
|
||||
String passphrase) {
|
||||
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
|
||||
SaveKeyringParcel saveParcel) {
|
||||
|
||||
OperationLog log = new OperationLog();
|
||||
int indent = 0;
|
||||
@@ -386,11 +399,16 @@ public class PgpKeyOperation {
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
|
||||
// If we have no passphrase, only allow restricted operation
|
||||
if (passphrase == null) {
|
||||
if (saveParcel.isRestrictedOnly()) {
|
||||
return internalRestricted(sKR, saveParcel, log);
|
||||
}
|
||||
|
||||
// Do we require a passphrase? If so, pass it along
|
||||
if (!isDivertToCard(masterSecretKey) && !mCryptoInput.hasPassphrase()) {
|
||||
return new PgpEditKeyResult(log, RequiredInputParcel.createRequiredPassphrase(
|
||||
masterSecretKey.getKeyID(), mCryptoInput.getSignatureTime()));
|
||||
}
|
||||
|
||||
// read masterKeyFlags, and use the same as before.
|
||||
// since this is the master key, this contains at least CERTIFY_OTHER
|
||||
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
|
||||
@@ -398,13 +416,13 @@ public class PgpKeyOperation {
|
||||
Date expiryTime = wsKR.getPublicKey().getExpiryTime();
|
||||
long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L;
|
||||
|
||||
return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log);
|
||||
return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, log);
|
||||
|
||||
}
|
||||
|
||||
private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
|
||||
int masterKeyFlags, long masterKeyExpiry,
|
||||
SaveKeyringParcel saveParcel, String passphrase,
|
||||
SaveKeyringParcel saveParcel,
|
||||
OperationLog log) {
|
||||
|
||||
int indent = 1;
|
||||
@@ -413,18 +431,25 @@ public class PgpKeyOperation {
|
||||
|
||||
PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
|
||||
|
||||
// 1. Unlock private key
|
||||
progress(R.string.progress_modify_unlock, 10);
|
||||
log.add(LogType.MSG_MF_UNLOCK, indent);
|
||||
PGPPrivateKey masterPrivateKey;
|
||||
{
|
||||
try {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
|
||||
} catch (PGPException e) {
|
||||
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
|
||||
if (isDivertToCard(masterSecretKey)) {
|
||||
masterPrivateKey = null;
|
||||
log.add(LogType.MSG_MF_DIVERT, indent);
|
||||
} else {
|
||||
|
||||
// 1. Unlock private key
|
||||
progress(R.string.progress_modify_unlock, 10);
|
||||
log.add(LogType.MSG_MF_UNLOCK, indent);
|
||||
{
|
||||
try {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mCryptoInput.getPassphrase());
|
||||
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
|
||||
} catch (PGPException e) {
|
||||
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,9 +504,16 @@ public class PgpKeyOperation {
|
||||
boolean isPrimary = saveParcel.mChangePrimaryUserId != null
|
||||
&& userId.equals(saveParcel.mChangePrimaryUserId);
|
||||
// generate and add new certificate
|
||||
PGPSignature cert = generateUserIdSignature(masterPrivateKey,
|
||||
masterPublicKey, userId, isPrimary, masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
|
||||
try {
|
||||
PGPSignature cert = generateUserIdSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, userId,
|
||||
isPrimary, masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
@@ -508,9 +540,15 @@ public class PgpKeyOperation {
|
||||
PGPUserAttributeSubpacketVector vector = attribute.getVector();
|
||||
|
||||
// generate and add new certificate
|
||||
PGPSignature cert = generateUserAttributeSignature(masterPrivateKey,
|
||||
masterPublicKey, vector);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
|
||||
try {
|
||||
PGPSignature cert = generateUserAttributeSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, vector);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
@@ -538,9 +576,15 @@ public class PgpKeyOperation {
|
||||
|
||||
// a duplicate revocation will be removed during canonicalization, so no need to
|
||||
// take care of that here.
|
||||
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
|
||||
masterPublicKey, userId);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
|
||||
try {
|
||||
PGPSignature cert = generateRevocationSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, userId);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, userId, cert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
@@ -610,11 +654,18 @@ public class PgpKeyOperation {
|
||||
log.add(LogType.MSG_MF_PRIMARY_REPLACE_OLD, indent);
|
||||
modifiedPublicKey = PGPPublicKey.removeCertification(
|
||||
modifiedPublicKey, userId, currentCert);
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
masterPrivateKey, masterPublicKey, userId, false,
|
||||
masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
try {
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, userId, false,
|
||||
masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -626,11 +677,17 @@ public class PgpKeyOperation {
|
||||
log.add(LogType.MSG_MF_PRIMARY_NEW, indent);
|
||||
modifiedPublicKey = PGPPublicKey.removeCertification(
|
||||
modifiedPublicKey, userId, currentCert);
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
masterPrivateKey, masterPublicKey, userId, true,
|
||||
masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
try {
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, userId, true,
|
||||
masterKeyFlags, masterKeyExpiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
ok = true;
|
||||
}
|
||||
|
||||
@@ -717,7 +774,8 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
PGPPublicKey pKey =
|
||||
updateMasterCertificates(masterPrivateKey, masterPublicKey,
|
||||
updateMasterCertificates(
|
||||
masterSecretKey, masterPrivateKey, masterPublicKey,
|
||||
flags, expiry, indent, log);
|
||||
if (pKey == null) {
|
||||
// error log entry has already been added by updateMasterCertificates itself
|
||||
@@ -755,9 +813,16 @@ public class PgpKeyOperation {
|
||||
pKey = PGPPublicKey.removeCertification(pKey, sig);
|
||||
}
|
||||
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
mCryptoInput.getPassphrase());
|
||||
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
||||
PGPSignature sig = generateSubkeyBindingSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPublicKey, masterPrivateKey, subPrivateKey, pKey, flags, expiry);
|
||||
|
||||
// generate and add new signature
|
||||
PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
|
||||
sKey, pKey, flags, expiry, passphrase);
|
||||
pKey = PGPPublicKey.addCertification(pKey, sig);
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
|
||||
}
|
||||
@@ -781,10 +846,17 @@ public class PgpKeyOperation {
|
||||
PGPPublicKey pKey = sKey.getPublicKey();
|
||||
|
||||
// generate and add new signature
|
||||
PGPSignature sig = generateRevocationSignature(masterPublicKey, masterPrivateKey, pKey);
|
||||
try {
|
||||
PGPSignature sig = generateRevocationSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPublicKey, masterPrivateKey, pKey);
|
||||
|
||||
pKey = PGPPublicKey.addCertification(pKey, sig);
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
|
||||
pKey = PGPPublicKey.addCertification(pKey, sig);
|
||||
sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
}
|
||||
subProgressPop();
|
||||
|
||||
@@ -827,19 +899,29 @@ public class PgpKeyOperation {
|
||||
|
||||
// add subkey binding signature (making this a sub rather than master key)
|
||||
PGPPublicKey pKey = keyPair.getPublicKey();
|
||||
PGPSignature cert = generateSubkeyBindingSignature(
|
||||
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
|
||||
add.mFlags, add.mExpiry);
|
||||
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
|
||||
try {
|
||||
PGPSignature cert = generateSubkeyBindingSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
|
||||
add.mFlags, add.mExpiry);
|
||||
pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
|
||||
PGPSecretKey sKey; {
|
||||
char[] passphrase = mCryptoInput.getPassphrase();
|
||||
if (passphrase == null) {
|
||||
passphrase = new char[] { };
|
||||
}
|
||||
// Build key encrypter and decrypter based on passphrase
|
||||
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder()
|
||||
.build().get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
||||
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
|
||||
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
||||
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
||||
|
||||
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
|
||||
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
|
||||
@@ -867,7 +949,7 @@ public class PgpKeyOperation {
|
||||
indent += 1;
|
||||
|
||||
sKR = applyNewUnlock(sKR, masterPublicKey, masterPrivateKey,
|
||||
passphrase, saveParcel.mNewUnlock, log, indent);
|
||||
mCryptoInput.getPassphrase(), saveParcel.mNewUnlock, log, indent);
|
||||
if (sKR == null) {
|
||||
// The error has been logged above, just return a bad state
|
||||
return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null);
|
||||
@@ -891,6 +973,12 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
progress(R.string.progress_done, 100);
|
||||
|
||||
if (!mNfcSignOps.isEmpty()) {
|
||||
log.add(LogType.MSG_MF_INPUT_REQUIRED, indent);
|
||||
return new PgpEditKeyResult(log, mNfcSignOps.build());
|
||||
}
|
||||
|
||||
log.add(LogType.MSG_MF_SUCCESS, indent);
|
||||
return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR));
|
||||
|
||||
@@ -967,7 +1055,7 @@ public class PgpKeyOperation {
|
||||
PGPSecretKeyRing sKR,
|
||||
PGPPublicKey masterPublicKey,
|
||||
PGPPrivateKey masterPrivateKey,
|
||||
String passphrase,
|
||||
char[] passphrase,
|
||||
ChangeUnlockParcel newUnlock,
|
||||
OperationLog log, int indent) throws PGPException {
|
||||
|
||||
@@ -1051,14 +1139,14 @@ public class PgpKeyOperation {
|
||||
private static PGPSecretKeyRing applyNewPassphrase(
|
||||
PGPSecretKeyRing sKR,
|
||||
PGPPublicKey masterPublicKey,
|
||||
String passphrase,
|
||||
char[] passphrase,
|
||||
String newPassphrase,
|
||||
OperationLog log, int indent) throws PGPException {
|
||||
|
||||
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
|
||||
.get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
|
||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase);
|
||||
// Build key encryptor based on new passphrase
|
||||
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
|
||||
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
|
||||
@@ -1115,8 +1203,9 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
/** Update all (non-revoked) uid signatures with new flags and expiry time. */
|
||||
private static PGPPublicKey updateMasterCertificates(
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey,
|
||||
private PGPPublicKey updateMasterCertificates(
|
||||
PGPSecretKey masterSecretKey, PGPPrivateKey masterPrivateKey,
|
||||
PGPPublicKey masterPublicKey,
|
||||
int flags, long expiry, int indent, OperationLog log)
|
||||
throws PGPException, IOException, SignatureException {
|
||||
|
||||
@@ -1172,10 +1261,16 @@ public class PgpKeyOperation {
|
||||
currentCert.getHashedSubPackets().isPrimaryUserID();
|
||||
modifiedPublicKey = PGPPublicKey.removeCertification(
|
||||
modifiedPublicKey, userId, currentCert);
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
try {
|
||||
PGPSignature newCert = generateUserIdSignature(
|
||||
getSignatureGenerator(masterSecretKey, mCryptoInput),
|
||||
mCryptoInput.getSignatureTime(),
|
||||
masterPrivateKey, masterPublicKey, userId, isPrimary, flags, expiry);
|
||||
modifiedPublicKey = PGPPublicKey.addCertification(
|
||||
modifiedPublicKey, userId, newCert);
|
||||
} catch (NfcInteractionNeeded e) {
|
||||
mNfcSignOps.addHash(e.hashToSign, e.hashAlgo);
|
||||
}
|
||||
ok = true;
|
||||
|
||||
}
|
||||
@@ -1190,15 +1285,37 @@ public class PgpKeyOperation {
|
||||
|
||||
}
|
||||
|
||||
private static PGPSignature generateUserIdSignature(
|
||||
private static PGPSignatureGenerator getSignatureGenerator(
|
||||
PGPSecretKey secretKey, CryptoInputParcel cryptoInput) {
|
||||
|
||||
PGPContentSignerBuilder builder;
|
||||
|
||||
S2K s2k = secretKey.getS2K();
|
||||
if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K
|
||||
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD) {
|
||||
// use synchronous "NFC based" SignerBuilder
|
||||
builder = new NfcSyncPGPContentSignerBuilder(
|
||||
secretKey.getPublicKey().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO,
|
||||
secretKey.getKeyID(), cryptoInput.getCryptoData())
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
} else {
|
||||
// content signer based on signing key algorithm and chosen hash algorithm
|
||||
builder = new JcaPGPContentSignerBuilder(
|
||||
secretKey.getPublicKey().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
}
|
||||
|
||||
return new PGPSignatureGenerator(builder);
|
||||
|
||||
}
|
||||
|
||||
private PGPSignature generateUserIdSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId, boolean primary,
|
||||
int flags, long expiry)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
{
|
||||
@@ -1222,7 +1339,7 @@ public class PgpKeyOperation {
|
||||
hashedPacketsGen.setPrimaryUserID(false, primary);
|
||||
|
||||
/* critical subpackets: we consider those important for a modern pgp implementation */
|
||||
hashedPacketsGen.setSignatureCreationTime(true, new Date());
|
||||
hashedPacketsGen.setSignatureCreationTime(true, creationTime);
|
||||
// Request that senders add the MDC to the message (authenticate unsigned messages)
|
||||
hashedPacketsGen.setFeature(true, Features.FEATURE_MODIFICATION_DETECTION);
|
||||
hashedPacketsGen.setKeyFlags(true, flags);
|
||||
@@ -1238,19 +1355,15 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
private static PGPSignature generateUserAttributeSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey,
|
||||
PGPUserAttributeSubpacketVector vector)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
{
|
||||
/* critical subpackets: we consider those important for a modern pgp implementation */
|
||||
hashedPacketsGen.setSignatureCreationTime(true, new Date());
|
||||
hashedPacketsGen.setSignatureCreationTime(true, creationTime);
|
||||
}
|
||||
|
||||
sGen.setHashedSubpackets(hashedPacketsGen.generate());
|
||||
@@ -1259,29 +1372,24 @@ public class PgpKeyOperation {
|
||||
}
|
||||
|
||||
private static PGPSignature generateRevocationSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId)
|
||||
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPrivateKey.getPublicKeyPacket().getAlgorithm(),
|
||||
PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
subHashedPacketsGen.setSignatureCreationTime(true, new Date());
|
||||
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
|
||||
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
|
||||
sGen.init(PGPSignature.CERTIFICATION_REVOCATION, masterPrivateKey);
|
||||
return sGen.generateCertification(userId, pKey);
|
||||
}
|
||||
|
||||
private static PGPSignature generateRevocationSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey pKey)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
|
||||
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
subHashedPacketsGen.setSignatureCreationTime(true, new Date());
|
||||
subHashedPacketsGen.setSignatureCreationTime(true, creationTime);
|
||||
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
|
||||
// Generate key revocation or subkey revocation, depending on master/subkey-ness
|
||||
if (masterPublicKey.getKeyID() == pKey.getKeyID()) {
|
||||
@@ -1293,26 +1401,12 @@ public class PgpKeyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
private static PGPSignature generateSubkeyBindingSignature(
|
||||
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
|
||||
PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, String passphrase)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
|
||||
passphrase.toCharArray());
|
||||
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
|
||||
return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey,
|
||||
pKey, flags, expiry);
|
||||
}
|
||||
|
||||
static PGPSignature generateSubkeyBindingSignature(
|
||||
PGPSignatureGenerator sGen, Date creationTime,
|
||||
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
|
||||
PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, long expiry)
|
||||
throws IOException, PGPException, SignatureException {
|
||||
|
||||
// date for signing
|
||||
Date creationTime = new Date();
|
||||
|
||||
PGPSignatureSubpacketGenerator unhashedPacketsGen = new PGPSignatureSubpacketGenerator();
|
||||
|
||||
// If this key can sign, we need a primary key binding signature
|
||||
@@ -1323,10 +1417,10 @@ public class PgpKeyOperation {
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
pKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
sGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
|
||||
sGen.setHashedSubpackets(subHashedPacketsGen.generate());
|
||||
PGPSignature certification = sGen.generateCertification(masterPublicKey, pKey);
|
||||
PGPSignatureGenerator subSigGen = new PGPSignatureGenerator(signerBuilder);
|
||||
subSigGen.init(PGPSignature.PRIMARYKEY_BINDING, subPrivateKey);
|
||||
subSigGen.setHashedSubpackets(subHashedPacketsGen.generate());
|
||||
PGPSignature certification = subSigGen.generateCertification(masterPublicKey, pKey);
|
||||
unhashedPacketsGen.setEmbeddedSignature(true, certification);
|
||||
}
|
||||
|
||||
@@ -1341,10 +1435,6 @@ public class PgpKeyOperation {
|
||||
}
|
||||
}
|
||||
|
||||
PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder(
|
||||
masterPublicKey.getAlgorithm(), PgpConstants.SECRET_KEY_SIGNATURE_HASH_ALGO)
|
||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||
PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder);
|
||||
sGen.init(PGPSignature.SUBKEY_BINDING, masterPrivateKey);
|
||||
sGen.setHashedSubpackets(hashedPacketsGen.generate());
|
||||
sGen.setUnhashedSubpackets(unhashedPacketsGen.generate());
|
||||
@@ -1371,4 +1461,10 @@ public class PgpKeyOperation {
|
||||
return flags;
|
||||
}
|
||||
|
||||
private static boolean isDivertToCard(PGPSecretKey secretKey) {
|
||||
S2K s2k = secretKey.getS2K();
|
||||
return s2k.getType() == S2K.GNU_DUMMY_S2K
|
||||
&& s2k.getProtectionMode() == S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user