From 08246e1b56e13e8851d9b5d6fe8679c113ab7d24 Mon Sep 17 00:00:00 2001 From: aw4y Date: Tue, 14 Jun 2016 22:59:25 +0100 Subject: [PATCH] Android N fix + cryptography with proper IV fix --- app/build.gradle | 4 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- .../java/net/rehacktive/waspdb/MainTest.java | 2 +- .../java/net/rehacktive/waspdb/WaspDb.java | 2 +- .../net/rehacktive/waspdb/WaspFactory.java | 2 +- .../java/net/rehacktive/waspdb/WaspHash.java | 6 ++- .../CipherManager.java | 41 ++++++++++++--- .../internals/collision/CollisionHash.java | 1 - .../internals/collision/KryoStoreUtils.java | 31 +++++++---- .../collision/exceptions/WaspDataPage.java | 27 ++++++++++ .../internals/cryptolayer/AESSerializer.java | 51 ------------------- .../waspdb/internals/utils/Utils.java | 4 +- 13 files changed, 95 insertions(+), 82 deletions(-) rename waspdb/src/main/java/net/rehacktive/waspdb/internals/{cryptolayer => collision}/CipherManager.java (54%) create mode 100644 waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/exceptions/WaspDataPage.java delete mode 100755 waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/AESSerializer.java diff --git a/app/build.gradle b/app/build.gradle index ec0a61d..efa760c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "net.rehacktive.waspdbexample" minSdkVersion 14 targetSdkVersion 22 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.1" } buildTypes { release { diff --git a/build.gradle b/build.gradle index e6c1aa5..4f09de2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' + classpath 'com.android.tools.build:gradle:2.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 274bee0..fab67e9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jul 27 17:20:00 BST 2015 +#Tue May 10 18:13:21 BST 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/waspdb/src/androidTest/java/net/rehacktive/waspdb/MainTest.java b/waspdb/src/androidTest/java/net/rehacktive/waspdb/MainTest.java index 22d3b0e..ac4fbdc 100644 --- a/waspdb/src/androidTest/java/net/rehacktive/waspdb/MainTest.java +++ b/waspdb/src/androidTest/java/net/rehacktive/waspdb/MainTest.java @@ -13,7 +13,7 @@ public class MainTest extends InstrumentationTestCase { String path; - String dbName = "justAtestDb"; + String dbName = "justAtestDb2"; String dbPwd = "passw0rd!"; Context ctx; diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/WaspDb.java b/waspdb/src/main/java/net/rehacktive/waspdb/WaspDb.java index 356dad9..94695a7 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/WaspDb.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/WaspDb.java @@ -1,6 +1,6 @@ package net.rehacktive.waspdb; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; +import net.rehacktive.waspdb.internals.collision.CipherManager; import net.rehacktive.waspdb.internals.utils.Utils; import java.io.File; diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/WaspFactory.java b/waspdb/src/main/java/net/rehacktive/waspdb/WaspFactory.java index 2661f2f..bcfd86d 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/WaspFactory.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/WaspFactory.java @@ -3,7 +3,7 @@ import android.os.AsyncTask; import net.rehacktive.waspdb.internals.collision.KryoStoreUtils; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; +import net.rehacktive.waspdb.internals.collision.CipherManager; import net.rehacktive.waspdb.internals.utils.Salt; import net.rehacktive.waspdb.internals.utils.Utils; diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/WaspHash.java b/waspdb/src/main/java/net/rehacktive/waspdb/WaspHash.java index 481293f..6158d76 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/WaspHash.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/WaspHash.java @@ -2,7 +2,7 @@ import net.rehacktive.waspdb.internals.collision.CollisionHash; import net.rehacktive.waspdb.internals.collision.exceptions.KeyNotFoundException; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; +import net.rehacktive.waspdb.internals.collision.CipherManager; import org.apache.commons.io.FileUtils; @@ -29,13 +29,15 @@ protected WaspHash(CipherManager cipherManager, String path) { * @param key the Object key * @param value the Object value */ - public void put(Object key, Object value) { + public Boolean put(Object key, Object value) { try { hash.updateObject(key, value); notifyObservers(); + return true; } catch(Exception e) { e.printStackTrace(); + return false; } } diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/CipherManager.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CipherManager.java similarity index 54% rename from waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/CipherManager.java rename to waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CipherManager.java index 66d78ac..d129c3c 100644 --- a/waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/CipherManager.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CipherManager.java @@ -1,4 +1,4 @@ -package net.rehacktive.waspdb.internals.cryptolayer; +package net.rehacktive.waspdb.internals.collision; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -11,9 +11,11 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; + /** * Created by stefano on 06/08/2014. */ @@ -22,14 +24,24 @@ public class CipherManager { private int ITERATIONS = 10000; private int KEYSIZE = 256; - public static String algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC"; + public static String cipher_algorithm = "AES/CBC/PKCS7PADDING"; + public static String key_algorithm = "PBKDF2WithHmacSHA1"; + public static String secretKeyAlgorithm = "AES"; protected Key key; protected static CipherManager instance = null; private CipherManager() { - // Exists only to defeat instantiation. +// Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1); +// Provider[] providers = Security.getProviders(); +// for (Provider provider : providers) { +// Log.i("CRYPTO","provider: "+provider.getName()); +// Set services = provider.getServices(); +// for (Provider.Service service : services) { +// Log.i("CRYPTO"," key_algorithm: "+service.getAlgorithm()); +// } +// } } public static CipherManager getInstance(char[] p, byte[] s) { @@ -47,18 +59,31 @@ public static CipherManager getInstance(char[] p, byte[] s) { } private void generateSK(char[] passPhrase, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException { - SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithm); + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(key_algorithm); KeySpec spec = new PBEKeySpec(passPhrase,salt,ITERATIONS, KEYSIZE); SecretKey secretKey = secretKeyFactory.generateSecret(spec); - key = new SecretKeySpec(secretKey.getEncoded(), algorithm); + key = new SecretKeySpec(secretKey.getEncoded(), secretKeyAlgorithm); + } + + protected Cipher getEncCipher() { + try { + Cipher cipher = Cipher.getInstance(cipher_algorithm); + cipher.init(Cipher.ENCRYPT_MODE, key); + + return cipher; + }catch (Exception e) { + e.printStackTrace(); + return null; + } } - protected Cipher getCipher(int mode) { + protected Cipher getDecCipher(byte[] iv) { try { - Cipher cipher = Cipher.getInstance(algorithm); - cipher.init(mode, key); + Cipher cipher = Cipher.getInstance(cipher_algorithm); + IvParameterSpec ivParams = new IvParameterSpec(iv); + cipher.init(Cipher.DECRYPT_MODE, key, ivParams); return cipher; }catch (Exception e) { diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CollisionHash.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CollisionHash.java index af463d9..a2abe4a 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CollisionHash.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/CollisionHash.java @@ -4,7 +4,6 @@ import net.rehacktive.waspdb.internals.collision.exceptions.KeyAlreadyExistsException; import net.rehacktive.waspdb.internals.collision.exceptions.KeyNotFoundException; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; import net.rehacktive.waspdb.internals.utils.Utils; import org.apache.commons.io.FileUtils; diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/KryoStoreUtils.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/KryoStoreUtils.java index dab58f9..a50602b 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/KryoStoreUtils.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/KryoStoreUtils.java @@ -4,13 +4,14 @@ import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; -import net.rehacktive.waspdb.internals.cryptolayer.AESSerializer; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; +import net.rehacktive.waspdb.internals.collision.exceptions.WaspDataPage; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import javax.crypto.Cipher; + public class KryoStoreUtils { @@ -18,9 +19,10 @@ public class KryoStoreUtils { private static Kryo kryoInstance; private static Kryo getKryoInstance() { - if(kryoInstance==null) + if(kryoInstance==null) { kryoInstance = new Kryo(); - + kryoInstance.register(WaspDataPage.class); + } return kryoInstance; } @@ -32,12 +34,15 @@ public static void serializeToDisk(Object obj, String filename, CipherManager ci //Log.d(TAG,start+": starting serializeToDisk with password"); Output output = new Output(new FileOutputStream(filename)); + WaspDataPage dataPage = new WaspDataPage(); if(cipherManager!=null) { - AESSerializer aes = new AESSerializer(getKryoInstance().getSerializer(obj.getClass()), cipherManager); - aes.write(getKryoInstance(), output, obj); + Cipher cipher = cipherManager.getEncCipher(); + dataPage.setIv(cipher.getIV()); + dataPage.setData(cipher.doFinal(serialize(obj))); } else { - getKryoInstance().writeObject(output, obj); + dataPage.setData(serialize(obj)); } + getKryoInstance().writeObject(output, dataPage); output.close(); //Long end = System.currentTimeMillis(); @@ -58,12 +63,13 @@ public static Object readFromDisk(String filename, Class type, CipherManager cip Object hash; if(f.exists()) { Input input = new Input(new FileInputStream(f)); + WaspDataPage dataPage = getKryoInstance().readObject(input, WaspDataPage.class); if(cipherManager!=null) { - AESSerializer aes = new AESSerializer(getKryoInstance().getDefaultSerializer(type), cipherManager); - hash = aes.read(getKryoInstance(), input, type); + Cipher decipher = cipherManager.getDecCipher(dataPage.getIv()); + hash = unserialize(decipher.doFinal(dataPage.getData()),type); } else { - hash = getKryoInstance().readObject(input, type); + hash = unserialize(dataPage.getData(),type); } input.close(); @@ -89,6 +95,11 @@ public static byte[] serialize(Object o) { getKryoInstance().writeObject(output, o); return output.toBytes(); } + + public static Object unserialize(byte[] buffer, Class type) { + Input input = new Input(buffer); + return getKryoInstance().readObject(input, type); + } // public static Object cloneObject(Object obj) { // return getKryoInstance().copy(obj); diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/exceptions/WaspDataPage.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/exceptions/WaspDataPage.java new file mode 100644 index 0000000..331ee2b --- /dev/null +++ b/waspdb/src/main/java/net/rehacktive/waspdb/internals/collision/exceptions/WaspDataPage.java @@ -0,0 +1,27 @@ +package net.rehacktive.waspdb.internals.collision.exceptions; + +/** + * Created by stefano on 14/06/2016. + */ + +public class WaspDataPage { + + private byte[] iv; + private byte[] data; + + public byte[] getIv() { + return iv; + } + + public void setIv(byte[] iv) { + this.iv = iv; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } +} diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/AESSerializer.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/AESSerializer.java deleted file mode 100755 index 608c2d1..0000000 --- a/waspdb/src/main/java/net/rehacktive/waspdb/internals/cryptolayer/AESSerializer.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.rehacktive.waspdb.internals.cryptolayer; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.KryoException; -import com.esotericsoftware.kryo.Serializer; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.Output; - -import java.io.IOException; - -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; - -public class AESSerializer extends Serializer { - - private final Serializer serializer; - private CipherManager cipherManager; - - public AESSerializer(Serializer serializer, CipherManager cm) { - this.serializer = serializer; - this.cipherManager = cm; - //Security.addProvider(new BouncyCastleProvider()); - } - - public void write(Kryo kryo, Output output, Object object) { - try { - CipherOutputStream cipherStream = new CipherOutputStream(output, cipherManager.getCipher(Cipher.ENCRYPT_MODE)); - - Output cipherOutput = new Output(cipherStream) { - public void close() throws KryoException { - // Don't allow the CipherOutputStream to close the output. - } - }; - kryo.writeObject(cipherOutput, object, serializer); - cipherOutput.flush(); - - cipherStream.close(); - } catch (IOException ex) { - throw new KryoException(ex); - } - - } - - public Object read(Kryo kryo, Input input, Class type) { - CipherInputStream cipherInput = new CipherInputStream(input, cipherManager.getCipher(Cipher.DECRYPT_MODE)); - return kryo.readObject(new Input(cipherInput), type, serializer); - } - - -} \ No newline at end of file diff --git a/waspdb/src/main/java/net/rehacktive/waspdb/internals/utils/Utils.java b/waspdb/src/main/java/net/rehacktive/waspdb/internals/utils/Utils.java index 1caf460..6a3bc9b 100755 --- a/waspdb/src/main/java/net/rehacktive/waspdb/internals/utils/Utils.java +++ b/waspdb/src/main/java/net/rehacktive/waspdb/internals/utils/Utils.java @@ -1,6 +1,6 @@ package net.rehacktive.waspdb.internals.utils; -import net.rehacktive.waspdb.internals.cryptolayer.CipherManager; +import net.rehacktive.waspdb.internals.collision.CipherManager; import java.io.File; import java.io.FileNotFoundException; @@ -49,7 +49,7 @@ public static boolean checkForCryptoAvailable() { // Security.addProvider(new BouncyCastleProvider()); // for(String s : Security.getAlgorithms("Cipher")) // System.out.println(s); - SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(CipherManager.algorithm); + SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(CipherManager.key_algorithm); return true; } catch (NoSuchAlgorithmException e) { return false;