Added ability to switch from native to java-only KDF.
@ -17,9 +17,11 @@ public abstract class MasterKey {
|
|||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
private static final Logger logger = Logger.get( MasterKey.class );
|
private static final Logger logger = Logger.get( MasterKey.class );
|
||||||
|
private static boolean allowNativeByDefault = true;
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final String fullName;
|
private final String fullName;
|
||||||
|
private boolean allowNative = allowNativeByDefault;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] masterKey;
|
private byte[] masterKey;
|
||||||
@ -46,6 +48,23 @@ public abstract class MasterKey {
|
|||||||
throw new UnsupportedOperationException( "Unsupported version: " + version );
|
throw new UnsupportedOperationException( "Unsupported version: " + version );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isAllowNativeByDefault() {
|
||||||
|
return allowNativeByDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native libraries are useful for speeding up the performance of cryptographical functions.
|
||||||
|
* Sometimes, however, we may prefer to use Java-only code.
|
||||||
|
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
|
||||||
|
* <p/>
|
||||||
|
* This setter affects the default setting for any newly created {@link MasterKey}s.
|
||||||
|
*
|
||||||
|
* @param allowNative false to disallow the use of native libraries.
|
||||||
|
*/
|
||||||
|
public static void setAllowNativeByDefault(final boolean allowNative) {
|
||||||
|
allowNativeByDefault = allowNative;
|
||||||
|
}
|
||||||
|
|
||||||
protected MasterKey(@NotNull final String fullName) {
|
protected MasterKey(@NotNull final String fullName) {
|
||||||
|
|
||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
@ -63,6 +82,15 @@ public abstract class MasterKey {
|
|||||||
return fullName;
|
return fullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAllowNative() {
|
||||||
|
return allowNative;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MasterKey setAllowNative(final boolean allowNative) {
|
||||||
|
this.allowNative = allowNative;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
protected byte[] getKey() {
|
protected byte[] getKey() {
|
||||||
|
|
||||||
|
@ -65,8 +65,15 @@ public class MasterKeyV0 extends MasterKey {
|
|||||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
||||||
|
|
||||||
|
return scrypt( masterKeySalt, mpBytes );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||||
try {
|
try {
|
||||||
|
if (isAllowNative())
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||||
|
else
|
||||||
|
return SCrypt.scryptJ( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||||
}
|
}
|
||||||
catch (GeneralSecurityException e) {
|
catch (GeneralSecurityException e) {
|
||||||
logger.bug( e );
|
logger.bug( e );
|
||||||
|
@ -48,15 +48,6 @@ public class MasterKeyV3 extends MasterKeyV2 {
|
|||||||
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
mpBytesBuf.get( mpBytes, 0, mpBytes.length );
|
||||||
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
Arrays.fill( mpBytesBuf.array(), (byte) 0 );
|
||||||
|
|
||||||
try {
|
return scrypt( masterKeySalt, mpBytes );
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, MP_N, MP_r, MP_p, MP_dkLen );
|
|
||||||
}
|
|
||||||
catch (GeneralSecurityException e) {
|
|
||||||
logger.bug( e );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Arrays.fill( mpBytes, (byte) 0 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,13 +12,13 @@
|
|||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:allowBackup="true">
|
android:allowBackup="true">
|
||||||
<activity android:name=".TestActivity" android:theme="@style/MPTheme">
|
<activity android:name=".EmergencyActivity" android:theme="@style/MPTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".EmergencyActivity" android:theme="@style/MPTheme" />
|
<activity android:name=".TestActivity" android:theme="@style/MPTheme" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 697 B |
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true"
|
||||||
@ -17,6 +18,13 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/img_identity" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/fullNameField"
|
android:id="@+id/fullNameField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -26,14 +34,14 @@
|
|||||||
android:hint="@string/fullName_hint"
|
android:hint="@string/fullName_hint"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="26sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@+id/rememberFullNameField"
|
android:id="@+id/rememberFullNameField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nextFocusForward="@+id/rememberPasswordField"
|
android:nextFocusForward="@+id/rememberPasswordField"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/remember" />
|
android:text="@string/remember" />
|
||||||
|
|
||||||
@ -46,16 +54,24 @@
|
|||||||
android:hint="@string/masterPassword_hint"
|
android:hint="@string/masterPassword_hint"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="18sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
android:id="@id/rememberPasswordField"
|
android:id="@id/rememberPasswordField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/forgetOnClose" />
|
android:text="@string/forgetOnClose" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/img_key" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@id/siteNameField"
|
android:id="@id/siteNameField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -65,7 +81,7 @@
|
|||||||
android:hint="@string/siteName_hint"
|
android:hint="@string/siteName_hint"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="18sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -76,7 +92,6 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_margin="20dp"
|
|
||||||
android:indeterminate="true" />
|
android:indeterminate="true" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -94,7 +109,7 @@
|
|||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="32sp"
|
android:textSize="32sp"
|
||||||
android:text="LuxdZozvDuma4["
|
tools:text="LuxdZozvDuma4["
|
||||||
android:onClick="copySitePassword" />
|
android:onClick="copySitePassword" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -104,7 +119,7 @@
|
|||||||
android:labelFor="@id/sitePasswordField"
|
android:labelFor="@id/sitePasswordField"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/sitePassword_hint" />
|
android:text="@string/sitePassword_hint" />
|
||||||
|
|
||||||
@ -115,55 +130,137 @@
|
|||||||
android:id="@+id/maskPasswordField"
|
android:id="@+id/maskPasswordField"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/maskPassword" />
|
android:text="@string/maskPassword" />
|
||||||
|
|
||||||
<Spinner
|
<ImageView
|
||||||
android:id="@id/siteTypeField"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nextFocusForward="@+id/counterField"
|
android:layout_marginTop="20dp"
|
||||||
android:gravity="center" />
|
android:layout_marginBottom="8dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/divider" />
|
||||||
|
|
||||||
<EditText
|
<LinearLayout
|
||||||
android:id="@id/counterField"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nextFocusForward="@+id/siteVersionField"
|
style="?android:buttonBarStyle"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@id/siteTypeField"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
style="?android:buttonBarButtonStyle"
|
||||||
|
android:nextFocusForward="@+id/counterField"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:inputType="text|textNoSuggestions"
|
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="18sp"
|
android:textSize="16sp"
|
||||||
android:text="1" />
|
android:drawableStart="@drawable/icon_key"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
tools:text="Long" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:labelFor="@id/counterField"
|
android:labelFor="@id/siteTypeField"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/siteCounter_hint" />
|
android:text="@string/siteType_hint" />
|
||||||
|
|
||||||
<Spinner
|
</LinearLayout>
|
||||||
android:id="@id/siteVersionField"
|
|
||||||
android:layout_width="match_parent"
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:nextFocusForward="@id/rememberFullNameField"
|
android:orientation="vertical"
|
||||||
android:gravity="center" />
|
android:gravity="center">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@id/counterField"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
style="?android:buttonBarButtonStyle"
|
||||||
|
android:nextFocusForward="@+id/siteVersionField"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:drawableStart="@drawable/icon_plus"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
tools:text="1" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:labelFor="@id/siteVersionField"
|
android:labelFor="@id/siteVersionField"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
|
android:text="@string/siteCounter_hint" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@id/siteVersionField"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
style="?android:buttonBarButtonStyle"
|
||||||
|
android:nextFocusForward="@+id/rememberFullNameField"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:drawableStart="@drawable/icon_gears"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
tools:text="3" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:labelFor="@id/siteVersionField"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/tertiary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/siteVersion_hint" />
|
android:text="@string/siteVersion_hint" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@string/btn_tests"
|
||||||
|
android:onClick="integrityTests"
|
||||||
|
android:background="@android:color/transparent" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fillViewport="true"
|
android:fillViewport="true"
|
||||||
@ -17,22 +18,31 @@
|
|||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/img_stats" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressView"
|
android:id="@+id/progressView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
style="@android:style/Widget.ProgressBar.Horizontal" />
|
tools:max="100"
|
||||||
|
tools:progress="80"
|
||||||
|
style="?android:progressBarStyleHorizontal" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/statusView"
|
android:id="@+id/statusView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:labelFor="@id/sitePasswordField"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:textSize="14sp"
|
android:textSize="12sp"
|
||||||
android:textColor="@android:color/secondary_text_dark"
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
android:text="@string/tests_testing" />
|
android:text="@string/tests_testing" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -55,6 +65,13 @@
|
|||||||
android:text="@string/tests_btn_testing"
|
android:text="@string/tests_btn_testing"
|
||||||
android:onClick="onAction" />
|
android:onClick="onAction" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/nativeKDF"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textColor="@android:color/tertiary_text_dark"
|
||||||
|
android:text="@string/nativeKDF" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
@ -8,15 +8,18 @@
|
|||||||
<string name="masterPassword_hint">Your master password</string>
|
<string name="masterPassword_hint">Your master password</string>
|
||||||
<string name="siteName_hint">eg. google.com</string>
|
<string name="siteName_hint">eg. google.com</string>
|
||||||
<string name="sitePassword_hint">Tap to copy</string>
|
<string name="sitePassword_hint">Tap to copy</string>
|
||||||
<string name="siteCounter_hint">Password #</string>
|
<string name="siteType_hint">Type</string>
|
||||||
|
<string name="siteCounter_hint">Counter</string>
|
||||||
<string name="siteVersion_hint">Algorithm</string>
|
<string name="siteVersion_hint">Algorithm</string>
|
||||||
<string name="empty" />
|
<string name="empty" />
|
||||||
|
<string name="btn_tests">Integrity Tests</string>
|
||||||
<string name="tests_unavailable">Test suite unavailable.</string>
|
<string name="tests_unavailable">Test suite unavailable.</string>
|
||||||
<string name="tests_btn_unavailable">Exit</string>
|
<string name="tests_btn_unavailable">Retest</string>
|
||||||
<string name="tests_testing">Testing device\'s password generation integrity…</string>
|
<string name="tests_testing">Testing device\'s password generation integrity…</string>
|
||||||
<string name="tests_btn_testing">Please Stand By…</string>
|
<string name="tests_btn_testing">Please Stand By…</string>
|
||||||
<string name="tests_failed">Incompatible device or OS.</string>
|
<string name="tests_failed">Incompatible device or OS.</string>
|
||||||
<string name="tests_btn_failed">Exit</string>
|
<string name="tests_btn_failed">Retest</string>
|
||||||
<string name="tests_passed">Integrity checks passed!</string>
|
<string name="tests_passed">Integrity checks passed!</string>
|
||||||
<string name="tests_btn_passed">Continue</string>
|
<string name="tests_btn_passed">Continue</string>
|
||||||
|
<string name="nativeKDF">Use native key derivation</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -61,13 +61,13 @@ public class EmergencyActivity extends Activity {
|
|||||||
EditText siteNameField;
|
EditText siteNameField;
|
||||||
|
|
||||||
@InjectView(R.id.siteTypeField)
|
@InjectView(R.id.siteTypeField)
|
||||||
Spinner siteTypeField;
|
Button siteTypeField;
|
||||||
|
|
||||||
@InjectView(R.id.counterField)
|
@InjectView(R.id.counterField)
|
||||||
EditText counterField;
|
Button counterField;
|
||||||
|
|
||||||
@InjectView(R.id.siteVersionField)
|
@InjectView(R.id.siteVersionField)
|
||||||
Spinner siteVersionField;
|
Button siteVersionField;
|
||||||
|
|
||||||
@InjectView(R.id.sitePasswordField)
|
@InjectView(R.id.sitePasswordField)
|
||||||
Button sitePasswordField;
|
Button sitePasswordField;
|
||||||
@ -104,9 +104,9 @@ public class EmergencyActivity extends Activity {
|
|||||||
fullNameField.setOnFocusChangeListener( updateMasterKey );
|
fullNameField.setOnFocusChangeListener( updateMasterKey );
|
||||||
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
|
masterPasswordField.setOnFocusChangeListener( updateMasterKey );
|
||||||
siteNameField.addTextChangedListener( updateSitePassword );
|
siteNameField.addTextChangedListener( updateSitePassword );
|
||||||
siteTypeField.setOnItemSelectedListener( updateSitePassword );
|
// siteTypeField.setOnItemSelectedListener( updateSitePassword );
|
||||||
counterField.addTextChangedListener( updateSitePassword );
|
counterField.addTextChangedListener( updateSitePassword );
|
||||||
siteVersionField.setOnItemSelectedListener( updateMasterKey );
|
// siteVersionField.setOnItemSelectedListener( updateMasterKey );
|
||||||
sitePasswordField.addTextChangedListener( new ValueChangedListener() {
|
sitePasswordField.addTextChangedListener( new ValueChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
void update() {
|
void update() {
|
||||||
@ -127,11 +127,11 @@ public class EmergencyActivity extends Activity {
|
|||||||
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
|
sitePasswordField.setTypeface( Res.sourceCodePro_Black );
|
||||||
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
sitePasswordField.setPaintFlags( sitePasswordField.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG );
|
||||||
|
|
||||||
siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
|
// siteTypeField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MPSiteType.forClass( MPSiteTypeClass.Generated ) ) );
|
||||||
siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
|
// siteTypeField.setSelection( MPSiteType.GeneratedLong.ordinal() );
|
||||||
|
|
||||||
siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
|
// siteVersionField.setAdapter( new ArrayAdapter<>( this, R.layout.spinner_item, MasterKey.Version.values() ) );
|
||||||
siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
|
// siteVersionField.setSelection( MasterKey.Version.CURRENT.ordinal() );
|
||||||
|
|
||||||
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
rememberFullNameField.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -162,6 +162,8 @@ public class EmergencyActivity extends Activity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
|
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
|
||||||
|
|
||||||
fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) );
|
fullNameField.setText( getPreferences( MODE_PRIVATE ).getString( "fullName", "" ) );
|
||||||
rememberFullNameField.setChecked( isRememberFullNameEnabled() );
|
rememberFullNameField.setChecked( isRememberFullNameEnabled() );
|
||||||
forgetPasswordField.setChecked( isForgetPasswordEnabled() );
|
forgetPasswordField.setChecked( isForgetPasswordEnabled() );
|
||||||
@ -195,6 +197,10 @@ public class EmergencyActivity extends Activity {
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isNativeKDFEnabled() {
|
||||||
|
return getPreferences( MODE_PRIVATE ).getBoolean( "nativeKDF", MasterKey.isAllowNativeByDefault() );
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isRememberFullNameEnabled() {
|
private boolean isRememberFullNameEnabled() {
|
||||||
return getPreferences( MODE_PRIVATE ).getBoolean( "rememberFullName", false );
|
return getPreferences( MODE_PRIVATE ).getBoolean( "rememberFullName", false );
|
||||||
}
|
}
|
||||||
@ -210,7 +216,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
private synchronized void updateMasterKey() {
|
private synchronized void updateMasterKey() {
|
||||||
final String fullName = fullNameField.getText().toString();
|
final String fullName = fullNameField.getText().toString();
|
||||||
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
final char[] masterPassword = masterPasswordField.getText().toString().toCharArray();
|
||||||
final MasterKey.Version version = (MasterKey.Version) siteVersionField.getSelectedItem();
|
final MasterKey.Version version = MasterKey.Version.CURRENT;//( MasterKey.Version) siteVersionField.getSelectedItem();
|
||||||
try {
|
try {
|
||||||
if (fullName.hashCode() == hc_userName && Arrays.hashCode( masterPassword ) == hc_masterPassword &&
|
if (fullName.hashCode() == hc_userName && Arrays.hashCode( masterPassword ) == hc_masterPassword &&
|
||||||
masterKeyFuture != null && masterKeyFuture.get().getAlgorithmVersion() == version)
|
masterKeyFuture != null && masterKeyFuture.get().getAlgorithmVersion() == version)
|
||||||
@ -265,8 +271,10 @@ public class EmergencyActivity extends Activity {
|
|||||||
|
|
||||||
private void updateSitePassword() {
|
private void updateSitePassword() {
|
||||||
final String siteName = siteNameField.getText().toString();
|
final String siteName = siteNameField.getText().toString();
|
||||||
final MPSiteType type = (MPSiteType) siteTypeField.getSelectedItem();
|
final MPSiteType type = MPSiteType.GeneratedLong;//(MPSiteType) siteTypeField.getSelectedItem();
|
||||||
final UnsignedInteger counter = UnsignedInteger.valueOf( ifNotNullElse( counterField.getText(), "1" ).toString() );
|
CharSequence counterText = counterField.getText();
|
||||||
|
final UnsignedInteger counter =
|
||||||
|
TextUtils.isEmpty( counterText )? UnsignedInteger.valueOf( 1L ): UnsignedInteger.valueOf( counterText.toString() );
|
||||||
|
|
||||||
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
|
if (masterKeyFuture == null || siteName.isEmpty() || type == null) {
|
||||||
sitePasswordField.setText( "" );
|
sitePasswordField.setText( "" );
|
||||||
@ -313,6 +321,10 @@ public class EmergencyActivity extends Activity {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void integrityTests(View view) {
|
||||||
|
TestActivity.startNoSkip( this );
|
||||||
|
}
|
||||||
|
|
||||||
public void copySitePassword(View view) {
|
public void copySitePassword(View view) {
|
||||||
final String currentSitePassword = this.sitePassword;
|
final String currentSitePassword = this.sitePassword;
|
||||||
if (TextUtils.isEmpty( currentSitePassword ))
|
if (TextUtils.isEmpty( currentSitePassword ))
|
||||||
|
@ -3,9 +3,10 @@ package com.lyndir.masterpassword;
|
|||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||||
|
|
||||||
import android.app.*;
|
import android.app.*;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.os.*;
|
import android.os.*;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.*;
|
import android.widget.*;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import butterknife.InjectView;
|
import butterknife.InjectView;
|
||||||
@ -22,6 +23,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
private static final Logger logger = Logger.get( TestActivity.class );
|
private static final Logger logger = Logger.get( TestActivity.class );
|
||||||
|
private static final String PREF_TESTS_PASSED = "integrityTestsPassed";
|
||||||
|
|
||||||
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
private final ListeningExecutorService backgroundExecutor = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor() );
|
||||||
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
|
private final ListeningExecutorService mainExecutor = MoreExecutors.listeningDecorator( new MainThreadExecutor() );
|
||||||
@ -38,20 +40,34 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
@InjectView(R.id.actionButton)
|
@InjectView(R.id.actionButton)
|
||||||
Button actionButton;
|
Button actionButton;
|
||||||
|
|
||||||
|
@InjectView(R.id.nativeKDF)
|
||||||
|
CheckBox nativeKDF;
|
||||||
|
|
||||||
private MPTestSuite testSuite;
|
private MPTestSuite testSuite;
|
||||||
private ListenableFuture<Boolean> testFuture;
|
private ListenableFuture<Boolean> testFuture;
|
||||||
private Runnable action;
|
private Runnable action;
|
||||||
private ImmutableSet<String> testNames;
|
private ImmutableSet<String> testNames;
|
||||||
|
|
||||||
|
public static void startNoSkip(Context context) {
|
||||||
|
context.startActivity( new Intent( context, TestActivity.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate( savedInstanceState );
|
super.onCreate( savedInstanceState );
|
||||||
Res.init( getResources() );
|
Res.init( getResources() );
|
||||||
|
|
||||||
getWindow().setFlags( WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE );
|
|
||||||
setContentView( R.layout.activity_test );
|
setContentView( R.layout.activity_test );
|
||||||
ButterKnife.inject( this );
|
ButterKnife.inject( this );
|
||||||
|
|
||||||
|
nativeKDF.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) {
|
||||||
|
getPreferences( MODE_PRIVATE ).edit().putBoolean( "nativeKDF", isChecked ).apply();
|
||||||
|
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setStatus( 0, 0, null );
|
setStatus( 0, 0, null );
|
||||||
testSuite = new MPTestSuite();
|
testSuite = new MPTestSuite();
|
||||||
@ -76,29 +92,26 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
|
|
||||||
final Set<String> integrityTestsPassed = getPreferences( MODE_PRIVATE ).getStringSet( "integrityTestsPassed",
|
|
||||||
ImmutableSet.<String>of() );
|
|
||||||
if (!FluentIterable.from( testNames ).anyMatch( new Predicate<String>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(@Nullable final String testName) {
|
|
||||||
return !integrityTestsPassed.contains( testName );
|
|
||||||
}
|
|
||||||
} )) {
|
|
||||||
// None of the tests we need to perform were missing from the tests that have already been passed on this device.
|
|
||||||
finish();
|
|
||||||
EmergencyActivity.start( TestActivity.this );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
if (testFuture == null) {
|
nativeKDF.setChecked( isNativeKDFEnabled() );
|
||||||
|
|
||||||
|
if (testFuture == null)
|
||||||
|
startTestSuite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNativeKDFEnabled() {
|
||||||
|
return getPreferences( MODE_PRIVATE ).getBoolean( "nativeKDF", MasterKey.isAllowNativeByDefault() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startTestSuite() {
|
||||||
|
if (testFuture != null)
|
||||||
|
testFuture.cancel( true );
|
||||||
|
|
||||||
|
MasterKey.setAllowNativeByDefault( isNativeKDFEnabled() );
|
||||||
|
|
||||||
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
setStatus( R.string.tests_testing, R.string.tests_btn_testing, null );
|
||||||
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
Futures.addCallback( testFuture = backgroundExecutor.submit( testSuite ), new FutureCallback<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
@ -107,7 +120,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
|
setStatus( R.string.tests_passed, R.string.tests_btn_passed, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
getPreferences( MODE_PRIVATE ).edit().putStringSet( "integrityTestsPassed", testNames ).apply();
|
getPreferences( MODE_PRIVATE ).edit().putStringSet( PREF_TESTS_PASSED, testNames ).apply();
|
||||||
finish();
|
finish();
|
||||||
EmergencyActivity.start( TestActivity.this );
|
EmergencyActivity.start( TestActivity.this );
|
||||||
}
|
}
|
||||||
@ -116,7 +129,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
|
setStatus( R.string.tests_failed, R.string.tests_btn_failed, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
finish();
|
startTestSuite();
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@ -133,7 +146,6 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
}
|
}
|
||||||
}, mainExecutor );
|
}, mainExecutor );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void onAction(View v) {
|
public void onAction(View v) {
|
||||||
if (action != null)
|
if (action != null)
|
||||||
|