From abd13d4d3d9d847985adb16f16e9cfbc5d3bd98f Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Wed, 29 Mar 2017 12:27:22 +0100 Subject: [PATCH] Crypto: refactor the Cipher class. Include the hmac in the cipher class. Derive keys on class creation instead of on encrypt/decrypt. --- .../journalmanager/BaseManager.java | 18 ++++--- .../syncadapter/journalmanager/Crypto.java | 52 ++++++++++--------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.java b/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.java index b65c5199..1b6acfc2 100644 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.java +++ b/app/src/main/java/com/etesync/syncadapter/journalmanager/BaseManager.java @@ -1,5 +1,8 @@ package com.etesync.syncadapter.journalmanager; +import com.etesync.syncadapter.App; +import com.etesync.syncadapter.GsonHelper; + import org.apache.commons.codec.Charsets; import java.io.ByteArrayOutputStream; @@ -7,9 +10,6 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.util.logging.Level; -import com.etesync.syncadapter.App; -import com.etesync.syncadapter.GsonHelper; - import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -19,8 +19,6 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; -import static com.etesync.syncadapter.journalmanager.Crypto.hmac; - abstract class BaseManager { final static protected MediaType JSON = MediaType.parse("application/json; charset=utf-8"); @@ -77,12 +75,14 @@ abstract class BaseManager { public String getContent(String keyBase64) { // FIXME: probably cache encryption object - return new String(new Crypto.Cipher().decrypt(keyBase64, content), Charsets.UTF_8); + Crypto.Cipher cipher = new Crypto.Cipher(keyBase64, null); + return new String(cipher.decrypt(content), Charsets.UTF_8); } void setContent(String keyBase64, String content) { // FIXME: probably cache encryption object - this.content = new Crypto.Cipher().encrypt(keyBase64, content.getBytes(Charsets.UTF_8)); + Crypto.Cipher cipher = new Crypto.Cipher(keyBase64, null); + this.content = cipher.encrypt(content.getBytes(Charsets.UTF_8)); } byte[] calculateHmac(String keyBase64, String uuid) { @@ -99,7 +99,9 @@ abstract class BaseManager { return "DEADBEEFDEADBEEFDEADBEEFDEADBEEF".getBytes(); } - return hmac(keyBase64, hashContent.toByteArray()); + // FIXME: probably cache encryption object + Crypto.Cipher cipher = new Crypto.Cipher(keyBase64, null); + return cipher.hmac(hashContent.toByteArray()); } protected Base() { diff --git a/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.java b/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.java index 591b2ee1..0a152d3e 100644 --- a/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.java +++ b/app/src/main/java/com/etesync/syncadapter/journalmanager/Crypto.java @@ -31,32 +31,22 @@ public class Crypto { return Base64.encodeToString(SCrypt.generate(password.getBytes(Charsets.UTF_8), salt.getBytes(Charsets.UTF_8), 16384, 8, 1, keySize), Base64.NO_WRAP); } - private static byte[] hmac256(byte[] keyByte, byte[] data) { - HMac hmac = new HMac(new SHA256Digest()); - KeyParameter key = new KeyParameter(keyByte); - byte[] ret = new byte[hmac.getMacSize()]; - hmac.init(key); - hmac.update(data, 0, data.length); - hmac.doFinal(ret, 0); - return ret; - } - - static byte[] hmac(String keyBase64, byte[] data) { - byte[] derivedKey = hmac256("hmac".getBytes(Charsets.UTF_8), Base64.decode(keyBase64, Base64.NO_WRAP)); - return hmac256(derivedKey, data); - } - static class Cipher { private SecureRandom _random = null; - - Cipher() { + private final byte[] cipherKey; + private final byte[] hmacKey; + + Cipher(String keyBase64, String salt) { + byte[] derivedKey; // FIXME use salt = hmac256(salt.getBytes(Charsets.UTF_8), Base64.decode(keyBase64, Base64.NO_WRAP)); + derivedKey = Base64.decode(keyBase64, Base64.NO_WRAP); + cipherKey = hmac256("aes".getBytes(Charsets.UTF_8), derivedKey); + hmacKey = hmac256("hmac".getBytes(Charsets.UTF_8), derivedKey); } private static final int blockSize = 16; // AES's block size in bytes - private BufferedBlockCipher getCipher(String keyBase64, byte[] iv, boolean encrypt) { - byte[] derivedKey = hmac256("aes".getBytes(Charsets.UTF_8), Base64.decode(keyBase64, Base64.NO_WRAP)); - KeyParameter key = new KeyParameter(derivedKey); + private BufferedBlockCipher getCipher(byte[] iv, boolean encrypt) { + KeyParameter key = new KeyParameter(cipherKey); CipherParameters params = new ParametersWithIV(key, iv); BlockCipherPadding padding = new PKCS7Padding(); @@ -68,11 +58,11 @@ public class Crypto { return cipher; } - byte[] decrypt(String keyBase64, byte[] _data) { + byte[] decrypt(byte[] _data) { byte[] iv = Arrays.copyOfRange(_data, 0, blockSize); byte[] data = Arrays.copyOfRange(_data, blockSize, _data.length); - BufferedBlockCipher cipher = getCipher(keyBase64, iv, false); + BufferedBlockCipher cipher = getCipher(iv, false); byte[] buf = new byte[cipher.getOutputSize(data.length)]; int len = cipher.processBytes(data, 0, data.length, buf, 0); @@ -91,11 +81,11 @@ public class Crypto { return out; } - byte[] encrypt(String keyBase64, byte[] data) { + byte[] encrypt(byte[] data) { byte[] iv = new byte[blockSize]; getRandom().nextBytes(iv); - BufferedBlockCipher cipher = getCipher(keyBase64, iv, true); + BufferedBlockCipher cipher = getCipher(iv, true); byte[] buf = new byte[cipher.getOutputSize(data.length) + blockSize]; System.arraycopy(iv, 0, buf, 0, iv.length); @@ -111,12 +101,26 @@ public class Crypto { return buf; } + byte[] hmac(byte[] data) { + return hmac256(hmacKey, data); + } + private SecureRandom getRandom() { if (_random == null) { _random = new SecureRandom(); } return _random; } + + private static byte[] hmac256(byte[] keyByte, byte[] data) { + HMac hmac = new HMac(new SHA256Digest()); + KeyParameter key = new KeyParameter(keyByte); + byte[] ret = new byte[hmac.getMacSize()]; + hmac.init(key); + hmac.update(data, 0, data.length); + hmac.doFinal(ret, 0); + return ret; + } } static String sha256(String base) {