From 36907660e874655f6d8b33d3d7329c8d6b03de5b Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sun, 7 Oct 2018 19:56:38 +0200 Subject: [PATCH] Restructure the code in the Slot classes a bit --- .../me/impy/aegis/crypto/CryptoUtils.java | 5 +- .../impy/aegis/crypto/SCryptParameters.java | 33 +++++++++++ .../me/impy/aegis/db/DatabaseManager.java | 1 - .../impy/aegis/db/slots/FingerprintSlot.java | 9 ++- .../me/impy/aegis/db/slots/PasswordSlot.java | 46 ++++++--------- .../java/me/impy/aegis/db/slots/RawSlot.java | 9 ++- .../java/me/impy/aegis/db/slots/Slot.java | 57 +++++++++++++------ .../java/me/impy/aegis/db/slots/SlotList.java | 20 +------ .../impy/aegis/ui/tasks/DerivationTask.java | 9 ++- 9 files changed, 120 insertions(+), 69 deletions(-) create mode 100644 app/src/main/java/me/impy/aegis/crypto/SCryptParameters.java diff --git a/app/src/main/java/me/impy/aegis/crypto/CryptoUtils.java b/app/src/main/java/me/impy/aegis/crypto/CryptoUtils.java index 0c0190c3..02811c89 100644 --- a/app/src/main/java/me/impy/aegis/crypto/CryptoUtils.java +++ b/app/src/main/java/me/impy/aegis/crypto/CryptoUtils.java @@ -30,15 +30,14 @@ public class CryptoUtils { public static final String CRYPTO_AEAD = "AES/GCM/NoPadding"; public static final byte CRYPTO_AEAD_KEY_SIZE = 32; public static final byte CRYPTO_AEAD_TAG_SIZE = 16; - public static final byte CRYPTO_AEAD_NONCE_SIZE = 12; public static final int CRYPTO_SCRYPT_N = 1 << 15; public static final int CRYPTO_SCRYPT_r = 8; public static final int CRYPTO_SCRYPT_p = 1; - public static SecretKey deriveKey(char[] password, byte[] salt, int n, int r, int p) { + public static SecretKey deriveKey(char[] password, SCryptParameters params) { byte[] bytes = toBytes(password); - byte[] keyBytes = SCrypt.generate(bytes, salt, n, r, p, CRYPTO_AEAD_KEY_SIZE); + byte[] keyBytes = SCrypt.generate(bytes, params.getSalt(), params.getN(), params.getR(), params.getP(), CRYPTO_AEAD_KEY_SIZE); return new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES"); } diff --git a/app/src/main/java/me/impy/aegis/crypto/SCryptParameters.java b/app/src/main/java/me/impy/aegis/crypto/SCryptParameters.java new file mode 100644 index 00000000..3b3f3a5a --- /dev/null +++ b/app/src/main/java/me/impy/aegis/crypto/SCryptParameters.java @@ -0,0 +1,33 @@ +package me.impy.aegis.crypto; + +import java.io.Serializable; + +public class SCryptParameters implements Serializable { + private int _n; + private int _r; + private int _p; + private byte[] _salt; + + public SCryptParameters(int n, int r, int p, byte[] salt) { + _n = n; + _r = r; + _p = p; + _salt = salt; + } + + public byte[] getSalt() { + return _salt; + } + + public int getN() { + return _n; + } + + public int getR() { + return _r; + } + + public int getP() { + return _p; + } +} diff --git a/app/src/main/java/me/impy/aegis/db/DatabaseManager.java b/app/src/main/java/me/impy/aegis/db/DatabaseManager.java index 0e2907a5..1958e682 100644 --- a/app/src/main/java/me/impy/aegis/db/DatabaseManager.java +++ b/app/src/main/java/me/impy/aegis/db/DatabaseManager.java @@ -58,7 +58,6 @@ public class DatabaseManager { public void lock() { assertState(false, true); - // TODO: properly clear everything _creds = null; _db = null; } diff --git a/app/src/main/java/me/impy/aegis/db/slots/FingerprintSlot.java b/app/src/main/java/me/impy/aegis/db/slots/FingerprintSlot.java index 37e8c3ca..8f185d63 100644 --- a/app/src/main/java/me/impy/aegis/db/slots/FingerprintSlot.java +++ b/app/src/main/java/me/impy/aegis/db/slots/FingerprintSlot.java @@ -1,11 +1,18 @@ package me.impy.aegis.db.slots; -public class FingerprintSlot extends RawSlot { +import java.util.UUID; +import me.impy.aegis.crypto.CryptParameters; + +public class FingerprintSlot extends RawSlot { public FingerprintSlot() { super(); } + FingerprintSlot(UUID uuid, byte[] key, CryptParameters keyParams) { + super(uuid, key, keyParams); + } + @Override public byte getType() { return TYPE_FINGERPRINT; diff --git a/app/src/main/java/me/impy/aegis/db/slots/PasswordSlot.java b/app/src/main/java/me/impy/aegis/db/slots/PasswordSlot.java index 88ae65a6..bb5cbf4d 100644 --- a/app/src/main/java/me/impy/aegis/db/slots/PasswordSlot.java +++ b/app/src/main/java/me/impy/aegis/db/slots/PasswordSlot.java @@ -3,60 +3,50 @@ package me.impy.aegis.db.slots; import org.json.JSONException; import org.json.JSONObject; +import java.util.UUID; + import javax.crypto.SecretKey; +import me.impy.aegis.crypto.CryptParameters; import me.impy.aegis.crypto.CryptoUtils; +import me.impy.aegis.crypto.SCryptParameters; import me.impy.aegis.encoding.Hex; import me.impy.aegis.encoding.HexException; public class PasswordSlot extends RawSlot { - private int _n; - private int _r; - private int _p; - private byte[] _salt; + private SCryptParameters _params; public PasswordSlot() { super(); } + protected PasswordSlot(UUID uuid, byte[] key, CryptParameters keyParams, SCryptParameters scryptParams) { + super(uuid, key, keyParams); + _params = scryptParams; + } + @Override public JSONObject toJson() { try { JSONObject obj = super.toJson(); - obj.put("n", _n); - obj.put("r", _r); - obj.put("p", _p); - obj.put("salt", Hex.encode(_salt)); + obj.put("n", _params.getN()); + obj.put("r", _params.getR()); + obj.put("p", _params.getP()); + obj.put("salt", Hex.encode(_params.getSalt())); return obj; } catch (JSONException e) { throw new RuntimeException(e); } } - @Override - public void deserialize(JSONObject obj) throws SlotException { - try { - super.deserialize(obj); - _n = obj.getInt("n"); - _r = obj.getInt("r"); - _p = obj.getInt("p"); - _salt = Hex.decode(obj.getString("salt")); - } catch (JSONException | HexException e) { - throw new SlotException(e); - } - } - - public SecretKey deriveKey(char[] password, byte[] salt, int n, int r, int p) { - SecretKey key = CryptoUtils.deriveKey(password, salt, n, r, p); - _n = n; - _r = r; - _p = p; - _salt = salt; + public SecretKey deriveKey(char[] password, SCryptParameters params) { + SecretKey key = CryptoUtils.deriveKey(password, params); + _params = params; return key; } public SecretKey deriveKey(char[] password) { - return CryptoUtils.deriveKey(password, _salt, _n, _r, _p); + return CryptoUtils.deriveKey(password, _params); } @Override diff --git a/app/src/main/java/me/impy/aegis/db/slots/RawSlot.java b/app/src/main/java/me/impy/aegis/db/slots/RawSlot.java index cbf83d1d..47cf81dc 100644 --- a/app/src/main/java/me/impy/aegis/db/slots/RawSlot.java +++ b/app/src/main/java/me/impy/aegis/db/slots/RawSlot.java @@ -1,11 +1,18 @@ package me.impy.aegis.db.slots; -public class RawSlot extends Slot { +import java.util.UUID; +import me.impy.aegis.crypto.CryptParameters; + +public class RawSlot extends Slot { public RawSlot() { super(); } + protected RawSlot(UUID uuid, byte[] key, CryptParameters keyParams) { + super(uuid, key, keyParams); + } + @Override public byte getType() { return TYPE_RAW; diff --git a/app/src/main/java/me/impy/aegis/db/slots/Slot.java b/app/src/main/java/me/impy/aegis/db/slots/Slot.java index 1ee06427..bdf81c43 100644 --- a/app/src/main/java/me/impy/aegis/db/slots/Slot.java +++ b/app/src/main/java/me/impy/aegis/db/slots/Slot.java @@ -21,6 +21,7 @@ import me.impy.aegis.crypto.CryptParameters; import me.impy.aegis.crypto.CryptResult; import me.impy.aegis.crypto.CryptoUtils; import me.impy.aegis.crypto.MasterKey; +import me.impy.aegis.crypto.SCryptParameters; import me.impy.aegis.encoding.Hex; import me.impy.aegis.encoding.HexException; @@ -29,14 +30,20 @@ public abstract class Slot implements Serializable { public final static byte TYPE_DERIVED = 0x01; public final static byte TYPE_FINGERPRINT = 0x02; - protected UUID _uuid; - protected byte[] _encryptedMasterKey; - protected CryptParameters _encryptedMasterKeyParams; + private UUID _uuid; + private byte[] _encryptedMasterKey; + private CryptParameters _encryptedMasterKeyParams; protected Slot() { _uuid = UUID.randomUUID(); } + protected Slot(UUID uuid, byte[] key, CryptParameters keyParams) { + _uuid = uuid; + _encryptedMasterKey = key; + _encryptedMasterKeyParams = keyParams; + } + // getKey decrypts the encrypted master key in this slot using the given cipher and returns it. public MasterKey getKey(Cipher cipher) throws SlotException, SlotIntegrityException { try { @@ -87,36 +94,54 @@ public abstract class Slot implements Serializable { public JSONObject toJson() { try { JSONObject obj = new JSONObject(); - JSONObject paramObj = _encryptedMasterKeyParams.toJson(); obj.put("type", getType()); obj.put("uuid", _uuid.toString()); obj.put("key", Hex.encode(_encryptedMasterKey)); - obj.put("key_params", paramObj); + obj.put("key_params", _encryptedMasterKeyParams.toJson()); return obj; } catch (JSONException e) { throw new RuntimeException(e); } } - public void deserialize(JSONObject obj) throws SlotException { + public static Slot fromJson(JSONObject obj) throws SlotException { + Slot slot; + try { - if (obj.getInt("type") != getType()) { - throw new SlotException("slot type mismatch"); - } - - // if there is no uuid, generate a new one + UUID uuid; if (!obj.has("uuid")) { - _uuid = UUID.randomUUID(); + uuid = UUID.randomUUID(); } else { - _uuid = UUID.fromString(obj.getString("uuid")); + uuid = UUID.fromString(obj.getString("uuid")); } - JSONObject paramObj = obj.getJSONObject("key_params"); - _encryptedMasterKey = Hex.decode(obj.getString("key")); - _encryptedMasterKeyParams = CryptParameters.fromJson(paramObj); + byte[] key = Hex.decode(obj.getString("key")); + CryptParameters keyParams = CryptParameters.fromJson(obj.getJSONObject("key_params")); + + switch (obj.getInt("type")) { + case Slot.TYPE_RAW: + slot = new RawSlot(uuid, key, keyParams); + break; + case Slot.TYPE_DERIVED: + SCryptParameters scryptParams = new SCryptParameters( + obj.getInt("n"), + obj.getInt("r"), + obj.getInt("p"), + Hex.decode(obj.getString("salt")) + ); + slot = new PasswordSlot(uuid, key, keyParams, scryptParams); + break; + case Slot.TYPE_FINGERPRINT: + slot = new FingerprintSlot(uuid, key, keyParams); + break; + default: + throw new SlotException("unrecognized slot type"); + } } catch (JSONException | HexException e) { throw new SlotException(e); } + + return slot; } public abstract byte getType(); diff --git a/app/src/main/java/me/impy/aegis/db/slots/SlotList.java b/app/src/main/java/me/impy/aegis/db/slots/SlotList.java index 8f8c721f..c4809e73 100644 --- a/app/src/main/java/me/impy/aegis/db/slots/SlotList.java +++ b/app/src/main/java/me/impy/aegis/db/slots/SlotList.java @@ -26,24 +26,8 @@ public class SlotList implements Iterable, Serializable { try { for (int i = 0; i < array.length(); i++) { - Slot slot; - JSONObject slotObj = array.getJSONObject(i); - - switch (slotObj.getInt("type")) { - case Slot.TYPE_RAW: - slot = new RawSlot(); - break; - case Slot.TYPE_DERIVED: - slot = new PasswordSlot(); - break; - case Slot.TYPE_FINGERPRINT: - slot = new FingerprintSlot(); - break; - default: - throw new SlotException("unrecognized slot type"); - } - - slot.deserialize(slotObj); + JSONObject obj = array.getJSONObject(i); + Slot slot = Slot.fromJson(obj); slots.add(slot); } } catch (SlotException | JSONException e) { diff --git a/app/src/main/java/me/impy/aegis/ui/tasks/DerivationTask.java b/app/src/main/java/me/impy/aegis/ui/tasks/DerivationTask.java index 73ed0065..794ff0c3 100644 --- a/app/src/main/java/me/impy/aegis/ui/tasks/DerivationTask.java +++ b/app/src/main/java/me/impy/aegis/ui/tasks/DerivationTask.java @@ -5,6 +5,7 @@ import android.content.Context; import javax.crypto.SecretKey; import me.impy.aegis.crypto.CryptoUtils; +import me.impy.aegis.crypto.SCryptParameters; import me.impy.aegis.db.slots.PasswordSlot; public class DerivationTask extends ProgressDialogTask { @@ -21,7 +22,13 @@ public class DerivationTask extends ProgressDialogTask