From 01b165ea88a032f31b8c2ff07351d3f893f6413d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 10 Feb 2016 17:08:00 +0100 Subject: performance: add license headers and some documentation --- .../SessionKeySecretKeyDecryptorBuilder.java | 9 +++++ .../keychain/pgp/CanonicalizedSecretKey.java | 14 +++++--- .../keychain/pgp/ComparableS2K.java | 40 +++++++++++++++++++--- .../keychain/pgp/PgpDecryptVerifyOperation.java | 1 + .../keychain/util/Passphrase.java | 22 +++++++++--- 5 files changed, 72 insertions(+), 14 deletions(-) (limited to 'OpenKeychain') diff --git a/OpenKeychain/src/main/java/org/spongycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java b/OpenKeychain/src/main/java/org/spongycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java index 49282230f..36fe06dfa 100644 --- a/OpenKeychain/src/main/java/org/spongycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java +++ b/OpenKeychain/src/main/java/org/spongycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java @@ -1,3 +1,9 @@ +/** + * Copyright (c) 2016 Vincent Breitmoser + * + * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. + */ + package org.spongycastle.openpgp.operator.jcajce; @@ -18,6 +24,9 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; +/** This is a builder for a special PBESecretKeyDecryptor which is parametrized by a + * fixed session key, which is used in place of the one obtained from a passphrase. + */ public class SessionKeySecretKeyDecryptorBuilder { private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 95a0d41cc..012a7e4e6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -38,6 +38,7 @@ import org.spongycastle.openpgp.operator.jcajce.SessionKeySecretKeyDecryptorBuil import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Passphrase; @@ -120,8 +121,13 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { } - // This method can potentially take a LONG time (i.e. seconds), so it should only - // ever be called by ProviderHelper to be cached in the database. + /** This method returns the SecretKeyType for this secret key, testing for an empty + * passphrase in the process. + * + * This method can potentially take a LONG time (i.e. seconds), so it should only + * ever be called by {@link ProviderHelper} for the purpose of caching its output + * in the database. + */ public SecretKeyType getSecretKeyTypeSuperExpensive() { S2K s2k = mSecretKey.getS2K(); if (s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K) { @@ -175,13 +181,13 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { } byte[] sessionKey; - sessionKey = passphrase.getCachedSessionKeyForAlgorithm(keyEncryptionAlgorithm, s2k); + sessionKey = passphrase.getCachedSessionKeyForParameters(keyEncryptionAlgorithm, s2k); if (sessionKey == null) { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider( Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray()); // this operation is EXPENSIVE, so we cache its result in the passed Passphrase object! sessionKey = keyDecryptor.makeKeyFromPassPhrase(keyEncryptionAlgorithm, s2k); - passphrase.addCachedSessionKey(keyEncryptionAlgorithm, s2k, sessionKey); + passphrase.addCachedSessionKeyForParameters(keyEncryptionAlgorithm, s2k, sessionKey); } PBESecretKeyDecryptor keyDecryptor = new SessionKeySecretKeyDecryptorBuilder() diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/ComparableS2K.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/ComparableS2K.java index 5c92008e5..31faa233c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/ComparableS2K.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/ComparableS2K.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2016 Vincent Breitmoser + * + * 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 . + */ + package org.sufficientlysecure.keychain.pgp; @@ -9,13 +26,26 @@ import android.os.Parcelable; import org.spongycastle.bcpg.S2K; +/** This is an immutable and parcelable class which stores the full s2k parametrization + * of an encrypted secret key, i.e. all fields of the {@link S2K} class (type, hash algo, + * iteration count, iv) plus the encryptionAlgorithm. This class is intended to be used + * as key in a HashMap for session key caching purposes, and overrides the + * {@link #hashCode} and {@link #equals} methods in a suitable way. + * + * Note that although it is a rather unlikely scenario that secret keys of the same key + * are encrypted with different ciphers, the encryption algorithm still determines the + * length of the specific session key and thus needs to be considered for purposes of + * session key caching. + * + * @see org.spongycastle.bcpg.S2K + */ public class ComparableS2K implements Parcelable { - int encryptionAlgorithm; - int s2kType; - int s2kHashAlgo; - long s2kItCount; - byte[] s2kIV; + private final int encryptionAlgorithm; + private final int s2kType; + private final int s2kHashAlgo; + private final long s2kItCount; + private final byte[] s2kIV; Integer cachedHashCode; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java index 3fc020aa7..f7a69612a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyOperation.java @@ -1,6 +1,7 @@ /* * Copyright (C) 2012-2014 Dominik Schürmann * Copyright (C) 2010-2014 Thialfihar + * Copyright (C) 2015-2016 Vincent Breitmoser * * 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 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java index bb54f8024..d47aefdfd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Passphrase.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Dominik Schürmann + * Copyright (C) 2016 Vincent Breitmoser * * 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 @@ -32,8 +33,13 @@ import java.util.Map.Entry; /** - * Passwords should not be stored as Strings in memory. - * This class wraps a char[] that can be erased after it is no longer used. + * This class wraps a char[] array that is overwritten before the object is freed, to avoid + * keeping passphrases in memory as much as possible. + * + * In addition to the raw passphrases, this class can cache the session key output of an applied + * S2K algorithm for a given set of S2K parameters. Since S2K operations are very expensive, this + * mechanism should be used to cache session keys whenever possible. + * * See also: *

* http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#PBEEx @@ -43,7 +49,7 @@ import java.util.Map.Entry; */ public class Passphrase implements Parcelable { private char[] mPassphrase; - HashMap mCachedSessionKeys; + private HashMap mCachedSessionKeys; /** * According to http://stackoverflow.com/a/15844273 EditText is not using String internally @@ -93,14 +99,20 @@ public class Passphrase implements Parcelable { return mPassphrase.length; } - public byte[] getCachedSessionKeyForAlgorithm(int keyEncryptionAlgorithm, S2K s2k) { + /** @return A cached session key, or null if none exists for the given parameters. */ + public byte[] getCachedSessionKeyForParameters(int keyEncryptionAlgorithm, S2K s2k) { if (mCachedSessionKeys == null) { return null; } return mCachedSessionKeys.get(new ComparableS2K(keyEncryptionAlgorithm, s2k)); } - public void addCachedSessionKey(int keyEncryptionAlgorithm, S2K s2k, byte[] sessionKey) { + /** Adds a session key for a set of s2k parameters to this Passphrase object's + * cache. The caller should make sure that the supplied session key is the result + * of an S2K operation applied to exactly the passphrase stored by this object + * with the given parameters. + */ + public void addCachedSessionKeyForParameters(int keyEncryptionAlgorithm, S2K s2k, byte[] sessionKey) { if (mCachedSessionKeys == null) { mCachedSessionKeys = new HashMap<>(); } -- cgit v1.2.3