diff --git a/app/src/main/cpp/monerujo.cpp b/app/src/main/cpp/monerujo.cpp index 164876ee..fac7c3b6 100644 --- a/app/src/main/cpp/monerujo.cpp +++ b/app/src/main/cpp/monerujo.cpp @@ -697,16 +697,21 @@ Java_com_m2049r_xmrwallet_model_Wallet_isSynchronized(JNIEnv *env, jobject insta //void cn_slow_hash(const void *data, size_t length, char *hash); // from crypto/hash-ops.h JNIEXPORT jbyteArray JNICALL -Java_com_m2049r_xmrwallet_util_KeyStoreHelper_cnSlowHash(JNIEnv *env, jobject clazz, - jbyteArray data) { +Java_com_m2049r_xmrwallet_util_KeyStoreHelper_slowHash(JNIEnv *env, jobject clazz, + jbyteArray data, jboolean broken) { + char hash[HASH_SIZE]; + jsize size = env->GetArrayLength(data); + if (broken && (size < 200 /*sizeof(union hash_state)*/)) { + return nullptr; + } jbyte *buffer = env->GetByteArrayElements(data, NULL); - jsize size = env->GetArrayLength(data); - char hash[HASH_SIZE]; - cn_slow_hash(buffer, (size_t) size, hash); - + if (broken) { + slow_hash_broken(buffer, hash); + } else { + slow_hash(buffer, (size_t) size, hash); + } env->ReleaseByteArrayElements(data, buffer, JNI_ABORT); // do not update java byte[] - jbyteArray result = env->NewByteArray(HASH_SIZE); env->SetByteArrayRegion(result, 0, HASH_SIZE, (jbyte *) hash); return result; diff --git a/app/src/main/cpp/monerujo.h b/app/src/main/cpp/monerujo.h index de74f221..24295fd1 100644 --- a/app/src/main/cpp/monerujo.h +++ b/app/src/main/cpp/monerujo.h @@ -60,7 +60,15 @@ enum { HASH_DATA_AREA = 136 }; -void cn_slow_hash(const void *data, size_t length, char *hash); +void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int prehashed); + +inline void slow_hash(const void *data, const size_t length, char *hash) { + cn_slow_hash(data, length, hash, 0 /* variant */, 0/*prehashed*/); +} + +inline void slow_hash_broken(const void *data, char *hash) { + cn_slow_hash(data, 200 /*sizeof(union hash_state)*/, hash, 1 /* variant */, 1 /*prehashed*/); +} #ifdef __cplusplus } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/FingerprintHelper.java b/app/src/main/java/com/m2049r/xmrwallet/util/FingerprintHelper.java index b0d480cd..33dcdc5b 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/FingerprintHelper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/FingerprintHelper.java @@ -24,7 +24,6 @@ public class FingerprintHelper { KeyStoreHelper.loadWalletUserPass(context, wallet); return true; } catch (KeyStoreHelper.BrokenPasswordStoreException ex) { - Timber.w(ex); return false; } } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java index 6abc6c61..596e8c05 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java @@ -302,6 +302,16 @@ public class Helper { else return ""; } + public static byte[] hexToBytes(String hex) { + final int len = hex.length(); + final byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + + Character.digit(hex.charAt(i + 1), 16)); + } + return data; + } + static public void setMoneroHome(Context context) { try { String home = getStorage(context, HOME_DIR).getAbsolutePath(); @@ -351,6 +361,12 @@ public class Helper { return crazyPass; } + // or maybe it is a broken CrAzYpass? + String brokenCrazyPass = KeyStoreHelper.getBrokenCrazyPass(context, password); + if (WalletManager.getInstance().verifyWalletPassword(walletPath, brokenCrazyPass, true)) { + return brokenCrazyPass; + } + return null; } diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/KeyStoreHelper.java b/app/src/main/java/com/m2049r/xmrwallet/util/KeyStoreHelper.java index eba00d44..0754d6ed 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/KeyStoreHelper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/KeyStoreHelper.java @@ -26,6 +26,7 @@ import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.support.annotation.NonNull; import android.util.Base64; +import android.util.Log; import java.io.IOException; import java.math.BigInteger; @@ -61,17 +62,21 @@ public class KeyStoreHelper { System.loadLibrary("monerujo"); } - public static native byte[] cnSlowHash(byte[] data); + public static native byte[] slowHash(byte[] data, boolean broken); static final private String RSA_ALIAS = "MonerujoRSA"; - public static String getCrazyPass(Context context, String password) { + private static String getCrazyPass(Context context, String password, boolean broken) { byte[] data = password.getBytes(StandardCharsets.UTF_8); byte[] sig = null; try { KeyStoreHelper.createKeys(context, RSA_ALIAS); sig = KeyStoreHelper.signData(RSA_ALIAS, data); - return CrazyPassEncoder.encode(cnSlowHash(sig)); + byte[] hash = slowHash(sig, broken); + if (hash == null) { + throw new IllegalStateException("Slow Hash is null!"); + } + return CrazyPassEncoder.encode(hash); } catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | KeyStoreException | InvalidKeyException | SignatureException ex) { @@ -79,6 +84,18 @@ public class KeyStoreHelper { } } + public static String getCrazyPass(Context context, String password) { + return getCrazyPass(context, password, false); + } + + public static String getBrokenCrazyPass(Context context, String password) { + // due to a link bug in the initial implementation, some crazypasses were built with + // prehash & variant == 1 + // since there are wallets out there, we need to keep this here + return getCrazyPass(context, password, true); + + } + public static boolean saveWalletUserPass(@NonNull Context context, String wallet, String password) { String walletKeyAlias = SecurityConstants.WALLET_PASS_KEY_PREFIX + wallet; byte[] data = password.getBytes(StandardCharsets.UTF_8);