New Passphrase class for safer passphrase handling in memory

This commit is contained in:
Dominik Schürmann 2015-03-19 03:03:46 +01:00
parent dbcb7a9e10
commit 9c9f95c7ac
34 changed files with 307 additions and 140 deletions

View File

@ -24,6 +24,7 @@ import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -101,7 +102,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface {
} }
@Override @Override
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException { public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
try { try {
long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId); long masterKeyId = mProviderHelper.getMasterKeyId(subKeyId);
return getCachedPassphrase(masterKeyId, subKeyId); return getCachedPassphrase(masterKeyId, subKeyId);
@ -111,7 +112,7 @@ public abstract class BaseOperation implements PassphraseCacheInterface {
} }
@Override @Override
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException { public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
try { try {
return PassphraseCacheService.getCachedPassphrase( return PassphraseCacheService.getCachedPassphrase(
mContext, masterKeyId, subKeyId); mContext, masterKeyId, subKeyId);

View File

@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyActio
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -79,7 +80,7 @@ public class CertifyOperation extends BaseOperation {
} }
// certification is always with the master key id, so use that one // certification is always with the master key id, so use that one
String passphrase = getCachedPassphrase(parcel.mMasterKeyId, parcel.mMasterKeyId); Passphrase passphrase = getCachedPassphrase(parcel.mMasterKeyId, parcel.mMasterKeyId);
if (!certificationKey.unlock(passphrase)) { if (!certificationKey.unlock(passphrase)) {
log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2); log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2);

View File

@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -55,7 +56,7 @@ public class EditKeyOperation extends BaseOperation {
super(context, providerHelper, progressable, cancelled); super(context, providerHelper, progressable, cancelled);
} }
public EditKeyResult execute(SaveKeyringParcel saveParcel, String passphrase) { public EditKeyResult execute(SaveKeyringParcel saveParcel, Passphrase passphrase) {
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
log.add(LogType.MSG_ED, 0); log.add(LogType.MSG_ED, 0);

View File

@ -22,6 +22,7 @@ import android.os.Parcel;
import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpMetadata;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
import org.sufficientlysecure.keychain.util.Passphrase;
public class DecryptVerifyResult extends OperationResult { public class DecryptVerifyResult extends OperationResult {
@ -37,7 +38,7 @@ public class DecryptVerifyResult extends OperationResult {
long mNfcSubKeyId; long mNfcSubKeyId;
byte[] mNfcSessionKey; byte[] mNfcSessionKey;
String mNfcPassphrase; Passphrase mNfcPassphrase;
OpenPgpSignatureResult mSignatureResult; OpenPgpSignatureResult mSignatureResult;
OpenPgpMetadata mDecryptMetadata; OpenPgpMetadata mDecryptMetadata;
@ -53,7 +54,7 @@ public class DecryptVerifyResult extends OperationResult {
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
} }
public void setNfcState(long subKeyId, byte[] sessionKey, String passphrase) { public void setNfcState(long subKeyId, byte[] sessionKey, Passphrase passphrase) {
mNfcSubKeyId = subKeyId; mNfcSubKeyId = subKeyId;
mNfcSessionKey = sessionKey; mNfcSessionKey = sessionKey;
mNfcPassphrase = passphrase; mNfcPassphrase = passphrase;
@ -67,7 +68,7 @@ public class DecryptVerifyResult extends OperationResult {
return mNfcSessionKey; return mNfcSessionKey;
} }
public String getNfcPassphrase() { public Passphrase getNfcPassphrase() {
return mNfcPassphrase; return mNfcPassphrase;
} }
@ -109,7 +110,7 @@ public class DecryptVerifyResult extends OperationResult {
mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); mSignatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader());
mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader()); mDecryptMetadata = source.readParcelable(OpenPgpMetadata.class.getClassLoader());
mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null; mNfcSessionKey = source.readInt() != 0 ? source.createByteArray() : null;
mNfcPassphrase = source.readString(); mNfcPassphrase = source.readParcelable(Passphrase.class.getClassLoader());
} }
public int describeContents() { public int describeContents() {
@ -127,7 +128,7 @@ public class DecryptVerifyResult extends OperationResult {
} else { } else {
dest.writeInt(0); dest.writeInt(0);
} }
dest.writeString(mNfcPassphrase); dest.writeParcelable(mNfcPassphrase, flags);
} }
public static final Creator<DecryptVerifyResult> CREATOR = new Creator<DecryptVerifyResult>() { public static final Creator<DecryptVerifyResult> CREATOR = new Creator<DecryptVerifyResult>() {

View File

@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.operations.results;
import android.os.Parcel; import android.os.Parcel;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.Date; import java.util.Date;
public class PgpSignEncryptResult extends OperationResult { public class PgpSignEncryptResult extends OperationResult {
@ -36,7 +38,7 @@ public class PgpSignEncryptResult extends OperationResult {
byte[] mNfcHash; byte[] mNfcHash;
int mNfcAlgo; int mNfcAlgo;
Date mNfcTimestamp; Date mNfcTimestamp;
String mNfcPassphrase; Passphrase mNfcPassphrase;
byte[] mDetachedSignature; byte[] mDetachedSignature;
public long getKeyIdPassphraseNeeded() { public long getKeyIdPassphraseNeeded() {
@ -47,7 +49,7 @@ public class PgpSignEncryptResult extends OperationResult {
mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; mKeyIdPassphraseNeeded = keyIdPassphraseNeeded;
} }
public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, String passphrase) { public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, Passphrase passphrase) {
mNfcKeyId = nfcKeyId; mNfcKeyId = nfcKeyId;
mNfcHash = nfcHash; mNfcHash = nfcHash;
mNfcAlgo = nfcAlgo; mNfcAlgo = nfcAlgo;
@ -75,7 +77,7 @@ public class PgpSignEncryptResult extends OperationResult {
return mNfcTimestamp; return mNfcTimestamp;
} }
public String getNfcPassphrase() { public Passphrase getNfcPassphrase() {
return mNfcPassphrase; return mNfcPassphrase;
} }

View File

@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -149,7 +150,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
/** /**
* Returns true on right passphrase * Returns true on right passphrase
*/ */
public boolean unlock(String passphrase) throws PgpGeneralException { public boolean unlock(Passphrase passphrase) throws PgpGeneralException {
// handle keys on OpenPGP cards like they were unlocked // handle keys on OpenPGP cards like they were unlocked
if (mSecretKey.getS2K() != null if (mSecretKey.getS2K() != null
&& mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K && mSecretKey.getS2K().getType() == S2K.GNU_DUMMY_S2K
@ -161,7 +162,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
// try to extract keys using the passphrase // try to extract keys using the passphrase
try { try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor); mPrivateKey = mSecretKey.extractPrivateKey(keyDecryptor);
mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED; mPrivateKeyState = PRIVATE_KEY_STATE_UNLOCKED;
} catch (PGPException e) { } catch (PGPException e) {

View File

@ -18,14 +18,16 @@
package org.sufficientlysecure.keychain.pgp; package org.sufficientlysecure.keychain.pgp;
import org.sufficientlysecure.keychain.util.Passphrase;
public interface PassphraseCacheInterface { public interface PassphraseCacheInterface {
public static class NoSecretKeyException extends Exception { public static class NoSecretKeyException extends Exception {
public NoSecretKeyException() { public NoSecretKeyException() {
} }
} }
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException; public Passphrase getCachedPassphrase(long subKeyId) throws NoSecretKeyException;
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException; public Passphrase getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException;
} }

View File

@ -60,6 +60,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@ -83,7 +84,7 @@ public class PgpDecryptVerify extends BaseOperation {
private OutputStream mOutStream; private OutputStream mOutStream;
private boolean mAllowSymmetricDecryption; private boolean mAllowSymmetricDecryption;
private String mPassphrase; private Passphrase mPassphrase;
private Set<Long> mAllowedKeyIds; private Set<Long> mAllowedKeyIds;
private boolean mDecryptMetadataOnly; private boolean mDecryptMetadataOnly;
private byte[] mDecryptedSessionKey; private byte[] mDecryptedSessionKey;
@ -118,7 +119,7 @@ public class PgpDecryptVerify extends BaseOperation {
private OutputStream mOutStream = null; private OutputStream mOutStream = null;
private Progressable mProgressable = null; private Progressable mProgressable = null;
private boolean mAllowSymmetricDecryption = true; private boolean mAllowSymmetricDecryption = true;
private String mPassphrase = null; private Passphrase mPassphrase = null;
private Set<Long> mAllowedKeyIds = null; private Set<Long> mAllowedKeyIds = null;
private boolean mDecryptMetadataOnly = false; private boolean mDecryptMetadataOnly = false;
private byte[] mDecryptedSessionKey = null; private byte[] mDecryptedSessionKey = null;
@ -159,7 +160,7 @@ public class PgpDecryptVerify extends BaseOperation {
return this; return this;
} }
public Builder setPassphrase(String passphrase) { public Builder setPassphrase(Passphrase passphrase) {
mPassphrase = passphrase; mPassphrase = passphrase;
return this; return this;
} }
@ -572,7 +573,7 @@ public class PgpDecryptVerify extends BaseOperation {
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder( PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(
digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( digestCalcProvider).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
mPassphrase.toCharArray()); mPassphrase.getCharArray());
clear = encryptedDataSymmetric.getDataStream(decryptorFactory); clear = encryptedDataSymmetric.getDataStream(decryptorFactory);
encryptedData = encryptedDataSymmetric; encryptedData = encryptedDataSymmetric;

View File

@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Primes; import org.sufficientlysecure.keychain.util.Primes;
import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.ProgressScaler;
@ -316,7 +317,7 @@ public class PgpKeyOperation {
masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator()); masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
subProgressPush(50, 100); subProgressPush(50, 100);
return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, "", log); return internal(sKR, masterSecretKey, add.mFlags, add.mExpiry, saveParcel, new Passphrase(), log);
} catch (PGPException e) { } catch (PGPException e) {
log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent); log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent);
@ -348,7 +349,7 @@ public class PgpKeyOperation {
* *
*/ */
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel,
String passphrase) { Passphrase passphrase) {
OperationLog log = new OperationLog(); OperationLog log = new OperationLog();
int indent = 0; int indent = 0;
@ -404,7 +405,7 @@ public class PgpKeyOperation {
private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey, private PgpEditKeyResult internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
int masterKeyFlags, long masterKeyExpiry, int masterKeyFlags, long masterKeyExpiry,
SaveKeyringParcel saveParcel, String passphrase, SaveKeyringParcel saveParcel, Passphrase passphrase,
OperationLog log) { OperationLog log) {
int indent = 1; int indent = 1;
@ -420,7 +421,7 @@ public class PgpKeyOperation {
{ {
try { try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor); masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) { } catch (PGPException e) {
log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1); log.add(LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
@ -839,7 +840,7 @@ public class PgpKeyOperation {
PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder() PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
.build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO); .build().get(PgpConstants.SECRET_KEY_SIGNATURE_CHECKSUM_HASH_ALGO);
@ -967,7 +968,7 @@ public class PgpKeyOperation {
PGPSecretKeyRing sKR, PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey, PGPPublicKey masterPublicKey,
PGPPrivateKey masterPrivateKey, PGPPrivateKey masterPrivateKey,
String passphrase, Passphrase passphrase,
ChangeUnlockParcel newUnlock, ChangeUnlockParcel newUnlock,
OperationLog log, int indent) throws PGPException { OperationLog log, int indent) throws PGPException {
@ -1051,20 +1052,20 @@ public class PgpKeyOperation {
private static PGPSecretKeyRing applyNewPassphrase( private static PGPSecretKeyRing applyNewPassphrase(
PGPSecretKeyRing sKR, PGPSecretKeyRing sKR,
PGPPublicKey masterPublicKey, PGPPublicKey masterPublicKey,
String passphrase, Passphrase passphrase,
String newPassphrase, Passphrase newPassphrase,
OperationLog log, int indent) throws PGPException { OperationLog log, int indent) throws PGPException {
PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build() PGPDigestCalculator encryptorHashCalc = new JcaPGPDigestCalculatorProviderBuilder().build()
.get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO); .get(PgpConstants.SECRET_KEY_ENCRYPTOR_HASH_ALGO);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());
// Build key encryptor based on new passphrase // Build key encryptor based on new passphrase
PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder( PBESecretKeyEncryptor keyEncryptorNew = new JcePBESecretKeyEncryptorBuilder(
PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc, PgpConstants.SECRET_KEY_ENCRYPTOR_SYMMETRIC_ALGO, encryptorHashCalc,
PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT) PgpConstants.SECRET_KEY_ENCRYPTOR_S2K_COUNT)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
newPassphrase.toCharArray()); newPassphrase.getCharArray());
// noinspection unchecked // noinspection unchecked
for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) { for (PGPSecretKey sKey : new IterableIterator<PGPSecretKey>(sKR.getSecretKeys())) {
@ -1295,11 +1296,11 @@ public class PgpKeyOperation {
private static PGPSignature generateSubkeyBindingSignature( private static PGPSignature generateSubkeyBindingSignature(
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey, PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, String passphrase) PGPSecretKey sKey, PGPPublicKey pKey, int flags, long expiry, Passphrase passphrase)
throws IOException, PGPException, SignatureException { throws IOException, PGPException, SignatureException {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
passphrase.toCharArray()); passphrase.getCharArray());
PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor); PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey, return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey,
pKey, flags, expiry); pKey, flags, expiry);

View File

@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp;
import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.CompressionAlgorithmTags;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.Date; import java.util.Date;
@ -29,12 +30,12 @@ public class PgpSignEncryptInput {
protected boolean mEnableAsciiArmorOutput = false; protected boolean mEnableAsciiArmorOutput = false;
protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED; protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED;
protected long[] mEncryptionMasterKeyIds = null; protected long[] mEncryptionMasterKeyIds = null;
protected String mSymmetricPassphrase = null; protected Passphrase mSymmetricPassphrase = null;
protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED; protected int mSymmetricEncryptionAlgorithm = PgpConstants.OpenKeychainSymmetricKeyAlgorithmTags.USE_PREFERRED;
protected long mSignatureMasterKeyId = Constants.key.none; protected long mSignatureMasterKeyId = Constants.key.none;
protected Long mSignatureSubKeyId = null; protected Long mSignatureSubKeyId = null;
protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED; protected int mSignatureHashAlgorithm = PgpConstants.OpenKeychainHashAlgorithmTags.USE_PREFERRED;
protected String mSignaturePassphrase = null; protected Passphrase mSignaturePassphrase = null;
protected long mAdditionalEncryptId = Constants.key.none; protected long mAdditionalEncryptId = Constants.key.none;
protected byte[] mNfcSignedHash = null; protected byte[] mNfcSignedHash = null;
protected Date mNfcCreationTimestamp = null; protected Date mNfcCreationTimestamp = null;
@ -73,11 +74,11 @@ public class PgpSignEncryptInput {
return this; return this;
} }
public String getSignaturePassphrase() { public Passphrase getSignaturePassphrase() {
return mSignaturePassphrase; return mSignaturePassphrase;
} }
public PgpSignEncryptInput setSignaturePassphrase(String signaturePassphrase) { public PgpSignEncryptInput setSignaturePassphrase(Passphrase signaturePassphrase) {
mSignaturePassphrase = signaturePassphrase; mSignaturePassphrase = signaturePassphrase;
return this; return this;
} }
@ -118,11 +119,11 @@ public class PgpSignEncryptInput {
return this; return this;
} }
public String getSymmetricPassphrase() { public Passphrase getSymmetricPassphrase() {
return mSymmetricPassphrase; return mSymmetricPassphrase;
} }
public PgpSignEncryptInput setSymmetricPassphrase(String symmetricPassphrase) { public PgpSignEncryptInput setSymmetricPassphrase(Passphrase symmetricPassphrase) {
mSymmetricPassphrase = symmetricPassphrase; mSymmetricPassphrase = symmetricPassphrase;
return this; return this;
} }

View File

@ -243,7 +243,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
log.add(LogType.MSG_PSE_SYMMETRIC, indent); log.add(LogType.MSG_PSE_SYMMETRIC, indent);
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().toCharArray()); new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().getCharArray());
cPk.addMethod(symmetricEncryptionGenerator); cPk.addMethod(symmetricEncryptionGenerator);
} else { } else {
log.add(LogType.MSG_PSE_ASYMMETRIC, indent); log.add(LogType.MSG_PSE_ASYMMETRIC, indent);

View File

@ -22,6 +22,8 @@ import android.net.Uri;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -57,12 +59,12 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable
mEnableAsciiArmorOutput = src.readInt() == 1; mEnableAsciiArmorOutput = src.readInt() == 1;
mCompressionId = src.readInt(); mCompressionId = src.readInt();
mEncryptionMasterKeyIds = src.createLongArray(); mEncryptionMasterKeyIds = src.createLongArray();
mSymmetricPassphrase = src.readString(); mSymmetricPassphrase = src.readParcelable(Passphrase.class.getClassLoader());
mSymmetricEncryptionAlgorithm = src.readInt(); mSymmetricEncryptionAlgorithm = src.readInt();
mSignatureMasterKeyId = src.readLong(); mSignatureMasterKeyId = src.readLong();
mSignatureSubKeyId = src.readInt() == 1 ? src.readLong() : null; mSignatureSubKeyId = src.readInt() == 1 ? src.readLong() : null;
mSignatureHashAlgorithm = src.readInt(); mSignatureHashAlgorithm = src.readInt();
mSignaturePassphrase = src.readString(); mSignaturePassphrase = src.readParcelable(Passphrase.class.getClassLoader());
mAdditionalEncryptId = src.readLong(); mAdditionalEncryptId = src.readLong();
mNfcSignedHash = src.createByteArray(); mNfcSignedHash = src.createByteArray();
mNfcCreationTimestamp = src.readInt() == 1 ? new Date(src.readLong()) : null; mNfcCreationTimestamp = src.readInt() == 1 ? new Date(src.readLong()) : null;
@ -112,7 +114,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable
dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0);
dest.writeInt(mCompressionId); dest.writeInt(mCompressionId);
dest.writeLongArray(mEncryptionMasterKeyIds); dest.writeLongArray(mEncryptionMasterKeyIds);
dest.writeString(mSymmetricPassphrase); dest.writeParcelable(mSymmetricPassphrase, flags);
dest.writeInt(mSymmetricEncryptionAlgorithm); dest.writeInt(mSymmetricEncryptionAlgorithm);
dest.writeLong(mSignatureMasterKeyId); dest.writeLong(mSignatureMasterKeyId);
if (mSignatureSubKeyId != null) { if (mSignatureSubKeyId != null) {
@ -122,7 +124,7 @@ public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable
dest.writeInt(0); dest.writeInt(0);
} }
dest.writeInt(mSignatureHashAlgorithm); dest.writeInt(mSignatureHashAlgorithm);
dest.writeString(mSignaturePassphrase); dest.writeParcelable(mSignaturePassphrase, flags);
dest.writeLong(mAdditionalEncryptId); dest.writeLong(mAdditionalEncryptId);
dest.writeByteArray(mNfcSignedHash); dest.writeByteArray(mNfcSignedHash);
if (mNfcCreationTimestamp != null) { if (mNfcCreationTimestamp != null) {

View File

@ -54,6 +54,7 @@ import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.ViewKeyActivity;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -179,7 +180,7 @@ public class OpenPgpService extends RemoteService {
return result; return result;
} }
private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, String pin, byte[] hashToSign, int hashAlgo) { private PendingIntent getNfcSignPendingIntent(Intent data, long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) {
// build PendingIntent for Yubikey NFC operations // build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class); Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_SIGN_HASH); intent.setAction(NfcActivity.ACTION_SIGN_HASH);
@ -195,7 +196,7 @@ public class OpenPgpService extends RemoteService {
PendingIntent.FLAG_CANCEL_CURRENT); PendingIntent.FLAG_CANCEL_CURRENT);
} }
private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, String pin, byte[] encryptedSessionKey) { private PendingIntent getNfcDecryptPendingIntent(Intent data, long subKeyId, Passphrase pin, byte[] encryptedSessionKey) {
// build PendingIntent for Yubikey NFC operations // build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getBaseContext(), NfcActivity.class); Intent intent = new Intent(getBaseContext(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);
@ -508,7 +509,7 @@ public class OpenPgpService extends RemoteService {
KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg)); KeychainContract.ApiAllowedKeys.buildBaseUri(currentPkg));
} }
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); Passphrase passphrase = data.getParcelableExtra(OpenPgpApi.EXTRA_PASSPHRASE);
long inputLength = is.available(); long inputLength = is.available();
InputData inputData = new InputData(is, inputLength); InputData inputData = new InputData(is, inputLength);

View File

@ -65,6 +65,7 @@ import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ParcelableFileCache; import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -281,7 +282,7 @@ public class KeychainIntentService extends IntentService implements Progressable
try { try {
/* Input */ /* Input */
String passphrase = data.getString(DECRYPT_PASSPHRASE); Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
InputData inputData = createDecryptInputData(data); InputData inputData = createDecryptInputData(data);
@ -411,7 +412,7 @@ public class KeychainIntentService extends IntentService implements Progressable
try { try {
/* Input */ /* Input */
String passphrase = data.getString(DECRYPT_PASSPHRASE); Passphrase passphrase = data.getParcelable(DECRYPT_PASSPHRASE);
byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY);
InputData inputData = createDecryptInputData(data); InputData inputData = createDecryptInputData(data);
@ -469,7 +470,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// Input // Input
SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL);
String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); Passphrase passphrase = data.getParcelable(EDIT_KEYRING_PASSPHRASE);
// Operation // Operation
EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled);

View File

@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import java.util.Date; import java.util.Date;
@ -121,7 +122,7 @@ public class PassphraseCacheService extends Service {
* new events to the alarm manager for new passphrases to let them timeout in the future. * new events to the alarm manager for new passphrases to let them timeout in the future.
*/ */
public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId, public static void addCachedPassphrase(Context context, long masterKeyId, long subKeyId,
String passphrase, Passphrase passphrase,
String primaryUserId) { String primaryUserId) {
Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId); Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + masterKeyId);
@ -143,7 +144,7 @@ public class PassphraseCacheService extends Service {
* @return passphrase or null (if no passphrase is cached for this keyId) * @return passphrase or null (if no passphrase is cached for this keyId)
*/ */
public static String getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException { public static Passphrase getCachedPassphrase(Context context, long masterKeyId, long subKeyId) throws KeyNotFoundException {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() for masterKeyId " Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() for masterKeyId "
+ masterKeyId + ", subKeyId " + subKeyId); + masterKeyId + ", subKeyId " + subKeyId);
@ -190,7 +191,9 @@ public class PassphraseCacheService extends Service {
switch (returnMessage.what) { switch (returnMessage.what) {
case MSG_PASSPHRASE_CACHE_GET_OKAY: case MSG_PASSPHRASE_CACHE_GET_OKAY:
return returnMessage.getData().getString(EXTRA_PASSPHRASE); Bundle returnData = returnMessage.getData();
returnData.setClassLoader(context.getClassLoader());
return returnData.getParcelable(EXTRA_PASSPHRASE);
case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND: case MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND:
throw new KeyNotFoundException(); throw new KeyNotFoundException();
default: default:
@ -202,11 +205,11 @@ public class PassphraseCacheService extends Service {
/** /**
* Internal implementation to get cached passphrase. * Internal implementation to get cached passphrase.
*/ */
private String getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException { private Passphrase getCachedPassphraseImpl(long masterKeyId, long subKeyId) throws ProviderHelper.NotFoundException {
// passphrase for symmetric encryption? // passphrase for symmetric encryption?
if (masterKeyId == Constants.key.symmetric) { if (masterKeyId == Constants.key.symmetric) {
Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption"); Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase(); Passphrase cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric).getPassphrase();
if (cachedPassphrase == null) { if (cachedPassphrase == null) {
return null; return null;
} }
@ -232,13 +235,13 @@ public class PassphraseCacheService extends Service {
case DIVERT_TO_CARD: case DIVERT_TO_CARD:
if (Preferences.getPreferences(this).useDefaultYubikeyPin()) { if (Preferences.getPreferences(this).useDefaultYubikeyPin()) {
Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456"); Log.d(Constants.TAG, "PassphraseCacheService: Using default Yubikey PIN: 123456");
return "123456"; // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/ return new Passphrase("123456"); // default Yubikey PIN, see http://www.yubico.com/2012/12/yubikey-neo-openpgp/
} else { } else {
Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN"); Log.d(Constants.TAG, "PassphraseCacheService: NOT using default Yubikey PIN");
break; break;
} }
case PASSPHRASE_EMPTY: case PASSPHRASE_EMPTY:
return ""; return new Passphrase("");
case UNAVAILABLE: case UNAVAILABLE:
throw new ProviderHelper.NotFoundException("secret key for this subkey is not available"); throw new ProviderHelper.NotFoundException("secret key for this subkey is not available");
case GNU_DUMMY: case GNU_DUMMY:
@ -331,7 +334,7 @@ public class PassphraseCacheService extends Service {
long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1); long masterKeyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1); long subKeyId = intent.getLongExtra(EXTRA_SUBKEY_ID, -1);
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE); Passphrase passphrase = intent.getParcelableExtra(EXTRA_PASSPHRASE);
String primaryUserID = intent.getStringExtra(EXTRA_USER_ID); String primaryUserID = intent.getStringExtra(EXTRA_USER_ID);
Log.d(Constants.TAG, Log.d(Constants.TAG,
@ -373,10 +376,10 @@ public class PassphraseCacheService extends Service {
Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!"); Log.e(Constants.TAG, "PassphraseCacheService: Bad request, missing masterKeyId or subKeyId!");
msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND; msg.what = MSG_PASSPHRASE_CACHE_GET_KEY_NOT_FOUND;
} else { } else {
String passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId); Passphrase passphrase = getCachedPassphraseImpl(masterKeyId, subKeyId);
msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY; msg.what = MSG_PASSPHRASE_CACHE_GET_OKAY;
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(EXTRA_PASSPHRASE, passphrase); bundle.putParcelable(EXTRA_PASSPHRASE, passphrase);
msg.setData(bundle); msg.setData(bundle);
} }
} catch (ProviderHelper.NotFoundException e) { } catch (ProviderHelper.NotFoundException e) {
@ -412,7 +415,10 @@ public class PassphraseCacheService extends Service {
* Called when one specific passphrase for keyId timed out * Called when one specific passphrase for keyId timed out
*/ */
private void timeout(Context context, long keyId) { private void timeout(Context context, long keyId) {
// remove passphrase corresponding to keyId from memory CachedPassphrase cPass = mPassphraseCache.get(keyId);
// clean internal char[] from memory!
cPass.getPassphrase().removeFromMemory();
// remove passphrase object
mPassphraseCache.remove(keyId); mPassphraseCache.remove(keyId);
Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!"); Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
@ -517,9 +523,9 @@ public class PassphraseCacheService extends Service {
public class CachedPassphrase { public class CachedPassphrase {
private String primaryUserID; private String primaryUserID;
private String passphrase; private Passphrase passphrase;
public CachedPassphrase(String passphrase, String primaryUserID) { public CachedPassphrase(Passphrase passphrase, String primaryUserID) {
setPassphrase(passphrase); setPassphrase(passphrase);
setPrimaryUserID(primaryUserID); setPrimaryUserID(primaryUserID);
} }
@ -528,7 +534,7 @@ public class PassphraseCacheService extends Service {
return primaryUserID; return primaryUserID;
} }
public String getPassphrase() { public Passphrase getPassphrase() {
return passphrase; return passphrase;
} }
@ -536,7 +542,7 @@ public class PassphraseCacheService extends Service {
this.primaryUserID = primaryUserID; this.primaryUserID = primaryUserID;
} }
public void setPassphrase(String passphrase) { public void setPassphrase(Passphrase passphrase) {
this.passphrase = passphrase; this.passphrase = passphrase;
} }
} }

View File

@ -22,6 +22,7 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
@ -296,33 +297,30 @@ public class SaveKeyringParcel implements Parcelable {
public static class ChangeUnlockParcel implements Parcelable { public static class ChangeUnlockParcel implements Parcelable {
// The new passphrase to use // The new passphrase to use
public final String mNewPassphrase; public final Passphrase mNewPassphrase;
// A new pin to use. Must only contain [0-9]+ // A new pin to use. Must only contain [0-9]+
public final String mNewPin; public final Passphrase mNewPin;
public ChangeUnlockParcel(String newPassphrase) { public ChangeUnlockParcel(Passphrase newPassphrase) {
this(newPassphrase, null); this(newPassphrase, null);
} }
public ChangeUnlockParcel(String newPassphrase, String newPin) { public ChangeUnlockParcel(Passphrase newPassphrase, Passphrase newPin) {
if (newPassphrase == null && newPin == null) { if (newPassphrase == null && newPin == null) {
throw new RuntimeException("Cannot set both passphrase and pin. THIS IS A BUG!"); throw new RuntimeException("Cannot set both passphrase and pin. THIS IS A BUG!");
} }
if (newPin != null && !newPin.matches("[0-9]+")) {
throw new RuntimeException("Pin must be numeric digits only. THIS IS A BUG!");
}
mNewPassphrase = newPassphrase; mNewPassphrase = newPassphrase;
mNewPin = newPin; mNewPin = newPin;
} }
public ChangeUnlockParcel(Parcel source) { public ChangeUnlockParcel(Parcel source) {
mNewPassphrase = source.readString(); mNewPassphrase = source.readParcelable(Passphrase.class.getClassLoader());
mNewPin = source.readString(); mNewPin = source.readParcelable(Passphrase.class.getClassLoader());
} }
@Override @Override
public void writeToParcel(Parcel destination, int flags) { public void writeToParcel(Parcel destination, int flags) {
destination.writeString(mNewPassphrase); destination.writeParcelable(mNewPassphrase, flags);
destination.writeString(mNewPin); destination.writeParcelable(mNewPin, flags);
} }
@Override @Override

View File

@ -62,6 +62,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -318,7 +319,7 @@ public class CertifyKeyFragment extends LoaderFragment
*/ */
private void initiateCertifying() { private void initiateCertifying() {
// get the user's passphrase for this key (if required) // get the user's passphrase for this key (if required)
String passphrase; Passphrase passphrase;
try { try {
passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId); passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(), mSignMasterKeyId, mSignMasterKeyId);
} catch (PassphraseCacheService.KeyNotFoundException e) { } catch (PassphraseCacheService.KeyNotFoundException e) {
@ -341,7 +342,6 @@ public class CertifyKeyFragment extends LoaderFragment
switch (requestCode) { switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: { case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
String passphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
startCertifying(); startCertifying();
} }
return; return;

View File

@ -23,11 +23,20 @@ import android.support.v4.app.FragmentTransaction;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import java.util.ArrayList;
public class CreateKeyActivity extends BaseActivity { public class CreateKeyActivity extends BaseActivity {
public static final String EXTRA_NAME = "name"; public static final String EXTRA_NAME = "name";
public static final String EXTRA_EMAIL = "email"; public static final String EXTRA_EMAIL = "email";
public class State {
String name;
String email;
ArrayList<String> additionalEmails;
char[] passphrase;
}
public static enum FragAction { public static enum FragAction {
START, START,
TO_RIGHT, TO_RIGHT,
@ -44,7 +53,7 @@ public class CreateKeyActivity extends BaseActivity {
getIntent().getStringExtra(EXTRA_NAME), getIntent().getStringExtra(EXTRA_NAME),
getIntent().getStringExtra(EXTRA_EMAIL) getIntent().getStringExtra(EXTRA_EMAIL)
); );
loadFragment(null, frag, FragAction.START); loadFragment(savedInstanceState, frag, FragAction.START);
} }
@Override @Override

View File

@ -85,7 +85,7 @@ public class CreateKeyEmailFragment extends Fragment {
*/ */
private static boolean isEditTextNotEmpty(Context context, EditText editText) { private static boolean isEditTextNotEmpty(Context context, EditText editText) {
boolean output = true; boolean output = true;
if (editText.getText().toString().length() == 0) { if (editText.getText().length() == 0) {
editText.setError(context.getString(R.string.create_key_empty)); editText.setError(context.getString(R.string.create_key_empty));
editText.requestFocus(); editText.requestFocus();
output = false; output = false;

View File

@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
import java.util.ArrayList; import java.util.ArrayList;
@ -72,7 +73,7 @@ public class CreateKeyFinalFragment extends Fragment {
String mName; String mName;
String mEmail; String mEmail;
ArrayList<String> mAdditionalEmails; ArrayList<String> mAdditionalEmails;
String mPassphrase; Passphrase mPassphrase;
SaveKeyringParcel mSaveKeyringParcel; SaveKeyringParcel mSaveKeyringParcel;
@ -81,14 +82,14 @@ public class CreateKeyFinalFragment extends Fragment {
*/ */
public static CreateKeyFinalFragment newInstance(String name, String email, public static CreateKeyFinalFragment newInstance(String name, String email,
ArrayList<String> additionalEmails, ArrayList<String> additionalEmails,
String passphrase) { Passphrase passphrase) {
CreateKeyFinalFragment frag = new CreateKeyFinalFragment(); CreateKeyFinalFragment frag = new CreateKeyFinalFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ARG_NAME, name); args.putString(ARG_NAME, name);
args.putString(ARG_EMAIL, email); args.putString(ARG_EMAIL, email);
args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails); args.putStringArrayList(ARG_ADDITIONAL_EMAILS, additionalEmails);
args.putString(ARG_PASSPHRASE, passphrase); args.putParcelable(ARG_PASSPHRASE, passphrase);
frag.setArguments(args); frag.setArguments(args);
@ -111,7 +112,7 @@ public class CreateKeyFinalFragment extends Fragment {
mName = getArguments().getString(ARG_NAME); mName = getArguments().getString(ARG_NAME);
mEmail = getArguments().getString(ARG_EMAIL); mEmail = getArguments().getString(ARG_EMAIL);
mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS); mAdditionalEmails = getArguments().getStringArrayList(ARG_ADDITIONAL_EMAILS);
mPassphrase = getArguments().getString(ARG_PASSPHRASE); mPassphrase = getArguments().getParcelable(ARG_PASSPHRASE);
// set values // set values
mNameEdit.setText(mName); mNameEdit.setText(mName);

View File

@ -68,7 +68,7 @@ public class CreateKeyNameFragment extends Fragment {
*/ */
private static boolean isEditTextNotEmpty(Context context, EditText editText) { private static boolean isEditTextNotEmpty(Context context, EditText editText) {
boolean output = true; boolean output = true;
if (editText.getText().toString().length() == 0) { if (editText.getText().length() == 0) {
editText.setError(context.getString(R.string.create_key_empty)); editText.setError(context.getString(R.string.create_key_empty));
editText.requestFocus(); editText.requestFocus();
output = false; output = false;
@ -79,19 +79,6 @@ public class CreateKeyNameFragment extends Fragment {
return output; return output;
} }
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
boolean output = true;
if (!editText1.getText().toString().equals(editText2.getText().toString())) {
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
editText2.requestFocus();
output = false;
} else {
editText2.setError(null);
}
return output;
}
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.create_key_name_fragment, container, false); View view = inflater.inflate(R.layout.create_key_name_fragment, container, false);

View File

@ -34,6 +34,7 @@ import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction; import org.sufficientlysecure.keychain.ui.CreateKeyActivity.FragAction;
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
@ -83,7 +84,7 @@ public class CreateKeyPassphraseFragment extends Fragment {
*/ */
private static boolean isEditTextNotEmpty(Context context, EditText editText) { private static boolean isEditTextNotEmpty(Context context, EditText editText) {
boolean output = true; boolean output = true;
if (editText.getText().toString().length() == 0) { if (editText.getText().length() == 0) {
editText.setError(context.getString(R.string.create_key_empty)); editText.setError(context.getString(R.string.create_key_empty));
editText.requestFocus(); editText.requestFocus();
output = false; output = false;
@ -95,11 +96,13 @@ public class CreateKeyPassphraseFragment extends Fragment {
} }
private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) { private static boolean areEditTextsEqual(Context context, EditText editText1, EditText editText2) {
boolean output = true; Passphrase p1 = new Passphrase(editText1);
if (!editText1.getText().toString().equals(editText2.getText().toString())) { Passphrase p2 = new Passphrase(editText2);
boolean output = (p1.equals(p2));
if (!output) {
editText2.setError(context.getString(R.string.create_key_passphrases_not_equal)); editText2.setError(context.getString(R.string.create_key_passphrases_not_equal));
editText2.requestFocus(); editText2.requestFocus();
output = false;
} else { } else {
editText2.setError(null); editText2.setError(null);
} }
@ -171,7 +174,7 @@ public class CreateKeyPassphraseFragment extends Fragment {
mName, mName,
mEmail, mEmail,
mAdditionalEmails, mAdditionalEmails,
mPassphraseEdit.getText().toString() new Passphrase(mPassphraseEdit.getText())
); );
hideKeyboard(); hideKeyboard();

View File

@ -191,7 +191,7 @@ public class DecryptFilesFragment extends DecryptFragment {
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -265,7 +265,7 @@ public class DecryptFilesFragment extends DecryptFragment {
data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal()); data.putInt(KeychainIntentService.TARGET, IOType.URI.ordinal());
data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri); data.putParcelable(KeychainIntentService.ENCRYPT_DECRYPT_OUTPUT_URI, mOutputUri);
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -341,7 +341,7 @@ public class DecryptFilesFragment extends DecryptFragment {
switch (requestCode) { switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: { case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
decryptOriginalFilename(); decryptOriginalFilename();
} }
return; return;

View File

@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
import org.sufficientlysecure.keychain.util.Passphrase;
public abstract class DecryptFragment extends Fragment { public abstract class DecryptFragment extends Fragment {
private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006; private static final int RESULT_CODE_LOOKUP_KEY = 0x00007006;
@ -57,7 +58,7 @@ public abstract class DecryptFragment extends Fragment {
// State // State
protected String mPassphrase; protected Passphrase mPassphrase;
protected byte[] mNfcDecryptedSessionKey; protected byte[] mNfcDecryptedSessionKey;
@Override @Override
@ -100,7 +101,7 @@ public abstract class DecryptFragment extends Fragment {
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
} }
protected void startNfcDecrypt(long subKeyId, String pin, byte[] encryptedSessionKey) { protected void startNfcDecrypt(long subKeyId, Passphrase pin, byte[] encryptedSessionKey) {
// build PendingIntent for Yubikey NFC operations // build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(getActivity(), NfcActivity.class); Intent intent = new Intent(getActivity(), NfcActivity.class);
intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY); intent.setAction(NfcActivity.ACTION_DECRYPT_SESSION_KEY);

View File

@ -161,7 +161,7 @@ public class DecryptTextFragment extends DecryptFragment {
// data // data
data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal()); data.putInt(KeychainIntentService.TARGET, IOType.BYTES.ordinal());
data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes()); data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, mCiphertext.getBytes());
data.putString(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase); data.putParcelable(KeychainIntentService.DECRYPT_PASSPHRASE, mPassphrase);
data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey); data.putByteArray(KeychainIntentService.DECRYPT_NFC_DECRYPTED_SESSION_KEY, mNfcDecryptedSessionKey);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
@ -247,7 +247,7 @@ public class DecryptTextFragment extends DecryptFragment {
case REQUEST_CODE_PASSPHRASE: { case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); mPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
decryptStart(); decryptStart();
} else { } else {
getActivity().finish(); getActivity().finish();

View File

@ -67,6 +67,7 @@ import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
public class EditKeyFragment extends LoaderFragment implements public class EditKeyFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
@ -100,7 +101,7 @@ public class EditKeyFragment extends LoaderFragment implements
private SaveKeyringParcel mSaveKeyringParcel; private SaveKeyringParcel mSaveKeyringParcel;
private String mPrimaryUserId; private String mPrimaryUserId;
private String mCurrentPassphrase; private Passphrase mCurrentPassphrase;
/** /**
* Creates new instance of this fragment * Creates new instance of this fragment
@ -267,7 +268,7 @@ public class EditKeyFragment extends LoaderFragment implements
switch (requestCode) { switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: { case REQUEST_CODE_PASSPHRASE: {
if (resultCode == Activity.RESULT_OK && data != null) { if (resultCode == Activity.RESULT_OK && data != null) {
mCurrentPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); mCurrentPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
// Prepare the loaders. Either re-connect with an existing ones, // Prepare the loaders. Either re-connect with an existing ones,
// or start new ones. // or start new ones.
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, EditKeyFragment.this);
@ -386,7 +387,7 @@ public class EditKeyFragment extends LoaderFragment implements
// cache new returned passphrase! // cache new returned passphrase!
mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel(
data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), (Passphrase) data.getParcelable(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE),
null null
); );
} }
@ -593,7 +594,7 @@ public class EditKeyFragment extends LoaderFragment implements
getActivity().finish(); getActivity().finish();
} }
private void saveInDatabase(String passphrase) { private void saveInDatabase(Passphrase passphrase) {
Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString()); Log.d(Constants.TAG, "mSaveKeyringParcel:\n" + mSaveKeyringParcel.toString());
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
@ -640,7 +641,7 @@ public class EditKeyFragment extends LoaderFragment implements
// fill values for this action // fill values for this action
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putString(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase); data.putParcelable(KeychainIntentService.EDIT_KEYRING_PASSPHRASE, passphrase);
data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel); data.putParcelable(KeychainIntentService.EDIT_KEYRING_PARCEL, mSaveKeyringParcel);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data); intent.putExtra(KeychainIntentService.EXTRA_DATA, data);

View File

@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.Date; import java.util.Date;
@ -41,7 +42,7 @@ public abstract class EncryptActivity extends BaseActivity {
public static final int REQUEST_CODE_NFC = 0x00008002; public static final int REQUEST_CODE_NFC = 0x00008002;
// For NFC data // For NFC data
protected String mSigningKeyPassphrase = null; protected Passphrase mSigningKeyPassphrase = null;
protected Date mNfcTimestamp = null; protected Date mNfcTimestamp = null;
protected byte[] mNfcHash = null; protected byte[] mNfcHash = null;
@ -64,7 +65,7 @@ public abstract class EncryptActivity extends BaseActivity {
startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
} }
protected void startNfcSign(long keyId, String pin, byte[] hashToSign, int hashAlgo) { protected void startNfcSign(long keyId, Passphrase pin, byte[] hashToSign, int hashAlgo) {
// build PendingIntent for Yubikey NFC operations // build PendingIntent for Yubikey NFC operations
Intent intent = new Intent(this, NfcActivity.class); Intent intent = new Intent(this, NfcActivity.class);
intent.setAction(NfcActivity.ACTION_SIGN_HASH); intent.setAction(NfcActivity.ACTION_SIGN_HASH);
@ -84,7 +85,7 @@ public abstract class EncryptActivity extends BaseActivity {
switch (requestCode) { switch (requestCode) {
case REQUEST_CODE_PASSPHRASE: { case REQUEST_CODE_PASSPHRASE: {
if (resultCode == RESULT_OK && data != null) { if (resultCode == RESULT_OK && data != null) {
mSigningKeyPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); mSigningKeyPassphrase = data.getParcelableExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE);
startEncrypt(); startEncrypt();
return; return;
} }

View File

@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui;
import android.net.Uri; import android.net.Uri;
import org.sufficientlysecure.keychain.util.Passphrase;
import java.util.ArrayList; import java.util.ArrayList;
public interface EncryptActivityInterface { public interface EncryptActivityInterface {
@ -39,7 +41,7 @@ public interface EncryptActivityInterface {
public void setEncryptionKeys(long[] encryptionKeys); public void setEncryptionKeys(long[] encryptionKeys);
public void setEncryptionUsers(String[] encryptionUsers); public void setEncryptionUsers(String[] encryptionUsers);
public void setPassphrase(String passphrase); public void setPassphrase(Passphrase passphrase);
// ArrayList on purpose as only those are parcelable // ArrayList on purpose as only those are parcelable
public ArrayList<Uri> getInputUris(); public ArrayList<Uri> getInputUris();

View File

@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ShareHelper; import org.sufficientlysecure.keychain.util.ShareHelper;
import java.util.ArrayList; import java.util.ArrayList;
@ -72,7 +73,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
private long mEncryptionKeyIds[] = null; private long mEncryptionKeyIds[] = null;
private String mEncryptionUserIds[] = null; private String mEncryptionUserIds[] = null;
private long mSigningKeyId = Constants.key.none; private long mSigningKeyId = Constants.key.none;
private String mPassphrase = ""; private Passphrase mPassphrase = new Passphrase();
private ArrayList<Uri> mInputUris; private ArrayList<Uri> mInputUris;
private ArrayList<Uri> mOutputUris; private ArrayList<Uri> mOutputUris;
@ -136,7 +137,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
} }
@Override @Override
public void setPassphrase(String passphrase) { public void setPassphrase(Passphrase passphrase) {
mPassphrase = passphrase; mPassphrase = passphrase;
} }
@ -243,8 +244,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi
if (isModeSymmetric()) { if (isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!"); Log.d(Constants.TAG, "Symmetric encryption enabled!");
String passphrase = mPassphrase; Passphrase passphrase = mPassphrase;
if (passphrase.length() == 0) { if (passphrase.isEmpty()) {
passphrase = null; passphrase = null;
} }
data.setSymmetricPassphrase(passphrase); data.setSymmetricPassphrase(passphrase);

View File

@ -28,6 +28,7 @@ import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Passphrase;
public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener { public class EncryptSymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener {
@ -67,8 +68,13 @@ public class EncryptSymmetricFragment extends Fragment implements EncryptActivit
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
// update passphrase in EncryptActivity // update passphrase in EncryptActivity
if (mPassphrase.getText().toString().equals(mPassphraseAgain.getText().toString())) { Passphrase p1 = new Passphrase(mPassphrase.getText());
mEncryptInterface.setPassphrase(s.toString()); Passphrase p2 = new Passphrase(mPassphraseAgain.getText());
boolean passesEquals = (p1.equals(p2));
p1.removeFromMemory();
p2.removeFromMemory();
if (passesEquals) {
mEncryptInterface.setPassphrase(new Passphrase(mPassphrase.getText()));
} else { } else {
mEncryptInterface.setPassphrase(null); mEncryptInterface.setPassphrase(null);
} }

View File

@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.pgp.PgpConstants;
import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.pgp.SignEncryptParcel;
import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.ShareHelper; import org.sufficientlysecure.keychain.util.ShareHelper;
import java.util.ArrayList; import java.util.ArrayList;
@ -70,7 +71,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
private String mEncryptionUserIds[] = null; private String mEncryptionUserIds[] = null;
// TODO Constants.key.none? What's wrong with a null value? // TODO Constants.key.none? What's wrong with a null value?
private long mSigningKeyId = Constants.key.none; private long mSigningKeyId = Constants.key.none;
private String mPassphrase = ""; private Passphrase mPassphrase = new Passphrase();
private ArrayList<Uri> mInputUris; private ArrayList<Uri> mInputUris;
private ArrayList<Uri> mOutputUris; private ArrayList<Uri> mOutputUris;
@ -134,7 +135,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
} }
@Override @Override
public void setPassphrase(String passphrase) { public void setPassphrase(Passphrase passphrase) {
mPassphrase.removeFromMemory();
mPassphrase = passphrase; mPassphrase = passphrase;
} }
@ -223,8 +225,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv
if (isModeSymmetric()) { if (isModeSymmetric()) {
Log.d(Constants.TAG, "Symmetric encryption enabled!"); Log.d(Constants.TAG, "Symmetric encryption enabled!");
String passphrase = mPassphrase; Passphrase passphrase = mPassphrase;
if (passphrase.length() == 0) { if (passphrase.isEmpty()) {
passphrase = null; passphrase = null;
} }
data.setSymmetricPassphrase(passphrase); data.setSymmetricPassphrase(passphrase);

View File

@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder; import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Preferences;
/** /**
@ -318,7 +319,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
positive.setOnClickListener(new View.OnClickListener() { positive.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final String passphrase = mPassphraseEditText.getText().toString(); final Passphrase passphrase = new Passphrase(mPassphraseEditText);
// Early breakout if we are dealing with a symmetric key // Early breakout if we are dealing with a symmetric key
if (mSecretRing == null) { if (mSecretRing == null) {
@ -395,7 +396,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
}); });
} }
private void finishCaching(String passphrase) { private void finishCaching(Passphrase passphrase) {
// any indication this isn't needed anymore, don't do it. // any indication this isn't needed anymore, don't do it.
if (mIsCancelled || getActivity() == null) { if (mIsCancelled || getActivity() == null) {
return; return;

View File

@ -45,6 +45,7 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText; import org.sufficientlysecure.keychain.ui.widget.PassphraseEditText;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Passphrase;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener { public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger"; private static final String ARG_MESSENGER = "messenger";
@ -67,12 +68,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
* @param messenger to communicate back after setting the passphrase * @param messenger to communicate back after setting the passphrase
* @return * @return
*/ */
public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) { public static SetPassphraseDialogFragment newInstance(Messenger messenger, Passphrase oldPassphrase, int title) {
SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment(); SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(ARG_TITLE, title); args.putInt(ARG_TITLE, title);
args.putParcelable(ARG_MESSENGER, messenger); args.putParcelable(ARG_MESSENGER, messenger);
args.putString(ARG_OLD_PASSPHRASE, oldPassphrase); args.putParcelable(ARG_OLD_PASSPHRASE, oldPassphrase);
frag.setArguments(args); frag.setArguments(args);
@ -88,7 +89,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
int title = getArguments().getInt(ARG_TITLE); int title = getArguments().getInt(ARG_TITLE);
mMessenger = getArguments().getParcelable(ARG_MESSENGER); mMessenger = getArguments().getParcelable(ARG_MESSENGER);
String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE); Passphrase oldPassphrase = getArguments().getParcelable(ARG_OLD_PASSPHRASE);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
@ -103,7 +104,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase); mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase);
if (TextUtils.isEmpty(oldPassphrase)) { if (oldPassphrase.isEmpty()) {
mNoPassphraseCheckBox.setChecked(true); mNoPassphraseCheckBox.setChecked(true);
mPassphraseEditText.setEnabled(false); mPassphraseEditText.setEnabled(false);
mPassphraseAgainEditText.setEnabled(false); mPassphraseAgainEditText.setEnabled(false);
@ -123,12 +124,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
dismiss(); dismiss();
String passphrase1; Passphrase passphrase1 = new Passphrase();
if (mNoPassphraseCheckBox.isChecked()) { if (mNoPassphraseCheckBox.isChecked()) {
passphrase1 = ""; passphrase1.setEmpty();
} else { } else {
passphrase1 = mPassphraseEditText.getText().toString(); passphrase1 = new Passphrase(mPassphraseEditText);
String passphrase2 = mPassphraseAgainEditText.getText().toString(); Passphrase passphrase2 = new Passphrase(mPassphraseAgainEditText);
if (!passphrase1.equals(passphrase2)) { if (!passphrase1.equals(passphrase2)) {
Toast.makeText( Toast.makeText(
activity, activity,
@ -139,7 +140,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
return; return;
} }
if (passphrase1.equals("")) { if (passphrase1.isEmpty()) {
Toast.makeText( Toast.makeText(
activity, activity,
getString(R.string.error_message, getString(R.string.error_message,
@ -152,7 +153,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
// return resulting data back to activity // return resulting data back to activity
Bundle data = new Bundle(); Bundle data = new Bundle();
data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1); data.putParcelable(MESSAGE_NEW_PASSPHRASE, passphrase1);
sendMessageToHandler(MESSAGE_OKAY, data); sendMessageToHandler(MESSAGE_OKAY, data);
} }

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.util;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.Editable;
import android.widget.EditText;
import org.sufficientlysecure.keychain.Constants;
import java.util.Arrays;
public class Passphrase implements Parcelable {
private char[] mPassphrase;
/**
* According to http://stackoverflow.com/a/15844273 EditText is not using String internally
* but char[]. Thus, we can get the char[] directly from it.
*/
public Passphrase(Editable editable) {
int pl = editable.length();
mPassphrase = new char[pl];
editable.getChars(0, pl, mPassphrase, 0);
// TODO: clean up internal char[] of EditText after getting the passphrase?
// editText.getText().replace()
System.gc();
}
public Passphrase(EditText editText) {
this(editText.getText());
}
public Passphrase(String passphrase) {
mPassphrase = passphrase.toCharArray();
}
public Passphrase() {
setEmpty();
}
public char[] getCharArray() {
return mPassphrase;
}
public boolean isEmpty() {
return (mPassphrase.length == 0);
}
public void setEmpty() {
removeFromMemory();
mPassphrase = new char[0];
}
public void removeFromMemory() {
if (mPassphrase != null) {
Arrays.fill(mPassphrase, ' ');
System.gc();
}
}
@Override
public String toString() {
if (Constants.DEBUG) {
return "Passphrase{" +
"mPassphrase=" + Arrays.toString(mPassphrase) +
'}';
} else {
return "Passphrase: hidden";
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Passphrase that = (Passphrase) o;
if (!Arrays.equals(mPassphrase, that.mPassphrase)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return mPassphrase != null ? Arrays.hashCode(mPassphrase) : 0;
}
private Passphrase(Parcel source) {
mPassphrase = source.createCharArray();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharArray(mPassphrase);
}
public static final Creator<Passphrase> CREATOR = new Creator<Passphrase>() {
public Passphrase createFromParcel(final Parcel source) {
return new Passphrase(source);
}
public Passphrase[] newArray(final int size) {
return new Passphrase[size];
}
};
public int describeContents() {
return 0;
}
}