Restructure the code in the Slot classes a bit

This commit is contained in:
Alexander Bakker 2018-10-07 19:56:38 +02:00
parent 0434513820
commit 36907660e8
9 changed files with 120 additions and 69 deletions

View file

@ -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");
}

View file

@ -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;
}
}

View file

@ -58,7 +58,6 @@ public class DatabaseManager {
public void lock() {
assertState(false, true);
// TODO: properly clear everything
_creds = null;
_db = null;
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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();

View file

@ -26,24 +26,8 @@ public class SlotList implements Iterable<Slot>, 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) {

View file

@ -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<DerivationTask.Params, SecretKey> {
@ -21,7 +22,13 @@ public class DerivationTask extends ProgressDialogTask<DerivationTask.Params, Se
Params params = args[0];
byte[] salt = CryptoUtils.generateSalt();
return params.getSlot().deriveKey(params.getPassword(), salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
SCryptParameters scryptParams = new SCryptParameters(
CryptoUtils.CRYPTO_SCRYPT_N,
CryptoUtils.CRYPTO_SCRYPT_r,
CryptoUtils.CRYPTO_SCRYPT_p,
salt
);
return params.getSlot().deriveKey(params.getPassword(), scryptParams);
}
@Override