diff --git a/platform-android/CMakeLists.txt b/platform-android/CMakeLists.txt index 0e00af43..97b5e491 100644 --- a/platform-android/CMakeLists.txt +++ b/platform-android/CMakeLists.txt @@ -5,6 +5,10 @@ add_library( mpw SHARED "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/base64.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/aes.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm.c" + "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm_v0.c" + "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm_v1.c" + "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm_v2.c" + "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-algorithm_v3.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-types.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-util.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal-util.c" diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java index 95386054..e0297010 100644 --- a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java +++ b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java @@ -316,8 +316,8 @@ public class EmergencyActivity extends Activity { @Override public void run() { try { - sitePassword = masterKey.siteResult( siteName, version.getAlgorithm(), counter, - MPKeyPurpose.Authentication, null, type, null ); + sitePassword = masterKey.siteResult( + siteName, version, counter, MPKeyPurpose.Authentication, null, type, null ); runOnUiThread( new Runnable() { @Override diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java index c792cb98..92a819d4 100644 --- a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java +++ b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java @@ -149,7 +149,7 @@ public final class Preferences { @Nonnull public MPResultType getDefaultResultType() { return MPResultType.values()[ - prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_result_type().ordinal() )]; + prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().mpw_default_result_type().ordinal() )]; } public boolean setDefaultVersion(final MPAlgorithm.Version value) { diff --git a/platform-independent/c/core/src/java/com_lyndir_masterpassword_MPAlgorithm_Version.h b/platform-independent/c/core/src/java/com_lyndir_masterpassword_MPAlgorithm_Version.h new file mode 100644 index 00000000..7fb59ba7 --- /dev/null +++ b/platform-independent/c/core/src/java/com_lyndir_masterpassword_MPAlgorithm_Version.h @@ -0,0 +1,47 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_lyndir_masterpassword_MPAlgorithm_Version */ + +#ifndef _Included_com_lyndir_masterpassword_MPAlgorithm_Version +#define _Included_com_lyndir_masterpassword_MPAlgorithm_Version +#ifdef __cplusplus +extern "C" { +#endif +#undef com_lyndir_masterpassword_MPAlgorithm_Version_AES_BLOCKSIZE +#define com_lyndir_masterpassword_MPAlgorithm_Version_AES_BLOCKSIZE 128L +/* + * Class: com_lyndir_masterpassword_MPAlgorithm_Version + * Method: _masterKey + * Signature: (Ljava/lang/String;[BI)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1masterKey + (JNIEnv *, jobject, jstring, jbyteArray, jint); + +/* + * Class: com_lyndir_masterpassword_MPAlgorithm_Version + * Method: _siteKey + * Signature: ([BLjava/lang/String;JILjava/lang/String;I)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteKey + (JNIEnv *, jobject, jbyteArray, jstring, jlong, jint, jstring, jint); + +/* + * Class: com_lyndir_masterpassword_MPAlgorithm_Version + * Method: _siteResult + * Signature: ([B[BLjava/lang/String;JILjava/lang/String;ILjava/lang/String;I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteResult + (JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint); + +/* + * Class: com_lyndir_masterpassword_MPAlgorithm_Version + * Method: _siteState + * Signature: ([B[BLjava/lang/String;JILjava/lang/String;ILjava/lang/String;I)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_MPAlgorithm_00024Version__1siteState + (JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform-independent/c/core/src/java/com_lyndir_masterpassword_impl_MPAlgorithmV0.h b/platform-independent/c/core/src/java/com_lyndir_masterpassword_impl_MPAlgorithmV0.h deleted file mode 100644 index a2a958a7..00000000 --- a/platform-independent/c/core/src/java/com_lyndir_masterpassword_impl_MPAlgorithmV0.h +++ /dev/null @@ -1,47 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_lyndir_masterpassword_impl_MPAlgorithmV0 */ - -#ifndef _Included_com_lyndir_masterpassword_impl_MPAlgorithmV0 -#define _Included_com_lyndir_masterpassword_impl_MPAlgorithmV0 -#ifdef __cplusplus -extern "C" { -#endif -#undef com_lyndir_masterpassword_impl_MPAlgorithmV0_AES_BLOCKSIZE -#define com_lyndir_masterpassword_impl_MPAlgorithmV0_AES_BLOCKSIZE 128L -/* - * Class: com_lyndir_masterpassword_impl_MPAlgorithmV0 - * Method: _masterKey - * Signature: (Ljava/lang/String;[BI)[B - */ -JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1masterKey - (JNIEnv *, jobject, jstring, jbyteArray, jint); - -/* - * Class: com_lyndir_masterpassword_impl_MPAlgorithmV0 - * Method: _siteKey - * Signature: ([BLjava/lang/String;JILjava/lang/String;I)[B - */ -JNIEXPORT jbyteArray JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteKey - (JNIEnv *, jobject, jbyteArray, jstring, jlong, jint, jstring, jint); - -/* - * Class: com_lyndir_masterpassword_impl_MPAlgorithmV0 - * Method: _siteResult - * Signature: ([B[BLjava/lang/String;JILjava/lang/String;ILjava/lang/String;I)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteResult - (JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint); - -/* - * Class: com_lyndir_masterpassword_impl_MPAlgorithmV0 - * Method: _siteState - * Signature: ([B[BLjava/lang/String;JILjava/lang/String;ILjava/lang/String;I)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1siteState - (JNIEnv *, jobject, jbyteArray, jbyteArray, jstring, jlong, jint, jstring, jint, jstring, jint); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/platform-independent/c/core/src/mpw-jni.c b/platform-independent/c/core/src/mpw-jni.c index b7ccec53..b84ee33a 100644 --- a/platform-independent/c/core/src/mpw-jni.c +++ b/platform-independent/c/core/src/mpw-jni.c @@ -1,6 +1,6 @@ #include -#include "java/com_lyndir_masterpassword_impl_MPAlgorithmV0.h" +#include "java/com_lyndir_masterpassword_MPAlgorithm_Version.h" #include "mpw-algorithm.h" #include "mpw-util.h" diff --git a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java index cb0051a7..c307f273 100644 --- a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java +++ b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java @@ -22,12 +22,15 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.strf; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import com.google.common.base.Charsets; import com.google.common.primitives.UnsignedInteger; import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import com.lyndir.lhunath.opal.system.MessageDigests; +import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.masterpassword.impl.*; -import java.nio.ByteOrder; -import java.nio.charset.Charset; +import java.nio.*; +import java.nio.charset.*; +import java.util.Arrays; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -36,7 +39,7 @@ import javax.annotation.Nullable; * @see Version */ @SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" }) -public abstract class MPAlgorithm { +public interface MPAlgorithm { /** * Derive a master key that describes a user's identity. @@ -45,7 +48,7 @@ public abstract class MPAlgorithm { * @param masterPassword The user's secret that authenticates his access to the identity. */ @Nullable - public abstract byte[] masterKey(String fullName, char[] masterPassword); + byte[] masterKey(String fullName, char[] masterPassword); /** * Derive a site key that describes a user's access to a specific entity. @@ -57,8 +60,8 @@ public abstract class MPAlgorithm { * @param keyContext An action-specific context within which to scope the key. */ @Nullable - public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, - MPKeyPurpose keyPurpose, @Nullable String keyContext); + byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, + MPKeyPurpose keyPurpose, @Nullable String keyContext); /** * Encode a templated result for a site key. @@ -67,9 +70,9 @@ public abstract class MPAlgorithm { * @param resultParam A parameter that provides contextual data specific to the type template. */ @Nullable - public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, - MPKeyPurpose keyPurpose, @Nullable String keyContext, - MPResultType resultType, @Nullable String resultParam); + String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, + MPKeyPurpose keyPurpose, @Nullable String keyContext, + MPResultType resultType, @Nullable String resultParam); /** * For {@link MPResultTypeClass#Stateful} {@code resultType}s, generate the {@code resultParam} to use with the @@ -80,9 +83,9 @@ public abstract class MPAlgorithm { * @param resultParam A parameter that provides contextual data specific to the type template. */ @Nullable - public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, - MPKeyPurpose keyPurpose, @Nullable String keyContext, - MPResultType resultType, String resultParam); + String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, + MPKeyPurpose keyPurpose, @Nullable String keyContext, + MPResultType resultType, String resultParam); // Configuration @@ -90,115 +93,105 @@ public abstract class MPAlgorithm { * The linear version identifier of this algorithm's implementation. */ @Nonnull - public abstract Version version(); + Version version(); /** * mpw: defaults: initial counter value. */ @Nonnull - public abstract UnsignedInteger mpw_default_counter(); + UnsignedInteger mpw_default_counter(); /** * mpw: defaults: password result type. */ @Nonnull - public abstract MPResultType mpw_default_result_type(); + MPResultType mpw_default_result_type(); /** * mpw: defaults: login result type. */ @Nonnull - public abstract MPResultType mpw_default_login_type(); + MPResultType mpw_default_login_type(); /** * mpw: defaults: answer result type. */ @Nonnull - public abstract MPResultType mpw_default_answer_type(); + MPResultType mpw_default_answer_type(); /** * mpw: Input character encoding. */ @Nonnull - public abstract Charset mpw_charset(); + Charset mpw_charset(); /** * mpw: Platform-agnostic byte order. */ @Nonnull - public abstract ByteOrder mpw_byteOrder(); + ByteOrder mpw_byteOrder(); /** * mpw: Key ID hash. */ @Nonnull - public abstract MessageDigests mpw_hash(); + MessageDigests mpw_hash(); /** * mpw: Site digest. */ @Nonnull - public abstract MessageAuthenticationDigests mpw_digest(); + MessageAuthenticationDigests mpw_digest(); /** * mpw: Master key size (byte). */ - public abstract int mpw_dkLen(); + int mpw_dkLen(); /** * mpw: Minimum size for derived keys (bit). */ - public abstract int mpw_keySize_min(); + int mpw_keySize_min(); /** * mpw: Maximum size for derived keys (bit). */ - public abstract int mpw_keySize_max(); + int mpw_keySize_max(); /** * mpw: validity for the time-based rolling counter (s). */ - public abstract long mpw_otp_window(); + long mpw_otp_window(); /** * scrypt: CPU cost parameter. */ - public abstract int scrypt_N(); + int scrypt_N(); /** * scrypt: Memory cost parameter. */ - public abstract int scrypt_r(); + int scrypt_r(); /** * scrypt: Parallelization parameter. */ - public abstract int scrypt_p(); + int scrypt_p(); // Utilities - @Nonnull - protected abstract byte[] toBytes(int number); + byte[] toBytes(final int number); - @Nonnull - protected abstract byte[] toBytes(UnsignedInteger number); + byte[] toBytes(final UnsignedInteger number); - @Nonnull - protected abstract byte[] toBytes(char[] characters); + byte[] toBytes(final char[] characters); - @Nonnull - protected abstract byte[] toID(byte[] bytes); - - @Override - public String toString() { - - return strf( "%d, %s", version().toInt(), getClass().getSimpleName() ); - } + byte[] toID(final byte[] bytes); /** * The algorithm iterations. */ - public enum Version { + enum Version implements MPAlgorithm { /** * bugs: @@ -206,38 +199,38 @@ public abstract class MPAlgorithm { * - miscounted the byte-length for multi-byte site names. * - miscounted the byte-length for multi-byte user names. */ - V0( new MPAlgorithmV0() ), + V0, /** * bugs: * - miscounted the byte-length for multi-byte site names. * - miscounted the byte-length for multi-byte user names. */ - V1( new MPAlgorithmV1() ), + V1, /** * bugs: * - miscounted the byte-length for multi-byte user names. */ - V2( new MPAlgorithmV2() ), + V2, /** * bugs: * - no known issues. */ - V3( new MPAlgorithmV3() ); + V3; public static final Version CURRENT = V3; - private final MPAlgorithm algorithm; + @SuppressWarnings("HardcodedFileSeparator") + private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding"; + private static final int AES_BLOCKSIZE = 128 /* bit */; - Version(final MPAlgorithm algorithm) { - this.algorithm = algorithm; + static { + Native.load( MPAlgorithm.class, "mpw" ); } - public MPAlgorithm getAlgorithm() { - return algorithm; - } + protected final Logger logger = Logger.get( getClass() ); @JsonCreator public static Version fromInt(final int algorithmVersion) { @@ -250,5 +243,207 @@ public abstract class MPAlgorithm { return ordinal(); } + + @Override + public String toString() { + + return strf( "%d, %s", version().toInt(), getClass().getSimpleName() ); + } + + @Nullable + @Override + public byte[] masterKey(final String fullName, final char[] masterPassword) { + + // Create a memory-safe NUL-terminated UTF-8 C-string byte array variant of masterPassword. + CharsetEncoder encoder = mpw_charset().newEncoder(); + byte[] masterPasswordBytes = new byte[(int) (masterPassword.length * (double) encoder.maxBytesPerChar()) + 1]; + try { + Arrays.fill( masterPasswordBytes, (byte) 0 ); + ByteBuffer masterPasswordBuffer = ByteBuffer.wrap( masterPasswordBytes ); + + CoderResult result = encoder.encode( CharBuffer.wrap( masterPassword ), masterPasswordBuffer, true ); + if (result.isError()) + throw new IllegalStateException( result.toString() ); + result = encoder.flush( masterPasswordBuffer ); + if (result.isError()) + throw new IllegalStateException( result.toString() ); + + return _masterKey( fullName, masterPasswordBytes, version().toInt() ); + } + finally { + Arrays.fill( masterPasswordBytes, (byte) 0 ); + } + } + + @Nullable + protected native byte[] _masterKey(final String fullName, final byte[] masterPassword, final int algorithmVersion); + + @Nullable + @Override + public byte[] siteKey(final byte[] masterKey, final String siteName, final UnsignedInteger siteCounter, + final MPKeyPurpose keyPurpose, @Nullable final String keyContext) { + + return _siteKey( masterKey, siteName, siteCounter.longValue(), keyPurpose.toInt(), keyContext, version().toInt() ); + } + + @Nullable + protected native byte[] _siteKey(final byte[] masterKey, final String siteName, final long siteCounter, + final int keyPurpose, @Nullable final String keyContext, final int version); + + @Nullable + @Override + public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter, + final MPKeyPurpose keyPurpose, @Nullable final String keyContext, + final MPResultType resultType, @Nullable final String resultParam) { + + return _siteResult( masterKey, siteKey, siteName, siteCounter.longValue(), + keyPurpose.toInt(), keyContext, resultType.getType(), resultParam, version().toInt() ); + } + + @Nullable + protected native String _siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter, + final int keyPurpose, @Nullable final String keyContext, + final int resultType, @Nullable final String resultParam, final int algorithmVersion); + + @Nullable + @Override + public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter, + final MPKeyPurpose keyPurpose, @Nullable final String keyContext, + final MPResultType resultType, final String resultParam) { + + return _siteState( masterKey, siteKey, siteName, siteCounter.longValue(), + keyPurpose.toInt(), keyContext, resultType.getType(), resultParam, version().toInt() ); + } + + @Nullable + protected native String _siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter, + final int keyPurpose, @Nullable final String keyContext, + final int resultType, final String resultParam, final int algorithmVersion); + + // Configuration + + @Nonnull + @Override + public Version version() { + return MPAlgorithm.Version.V0; + } + + @Nonnull + @Override + public UnsignedInteger mpw_default_counter() { + return UnsignedInteger.ONE; + } + + @Nonnull + @Override + public MPResultType mpw_default_result_type() { + return MPResultType.GeneratedLong; + } + + @Nonnull + @Override + public MPResultType mpw_default_login_type() { + return MPResultType.GeneratedName; + } + + @Nonnull + @Override + public MPResultType mpw_default_answer_type() { + return MPResultType.GeneratedPhrase; + } + + @Nonnull + @Override + public Charset mpw_charset() { + return Charsets.UTF_8; + } + + @Nonnull + @Override + public ByteOrder mpw_byteOrder() { + return ByteOrder.BIG_ENDIAN; + } + + @Nonnull + @Override + public MessageDigests mpw_hash() { + return MessageDigests.SHA256; + } + + @Nonnull + @Override + public MessageAuthenticationDigests mpw_digest() { + return MessageAuthenticationDigests.HmacSHA256; + } + + @Override + @SuppressWarnings("MagicNumber") + public int mpw_dkLen() { + return 64; + } + + @Override + @SuppressWarnings("MagicNumber") + public int mpw_keySize_min() { + return 128; + } + + @Override + @SuppressWarnings("MagicNumber") + public int mpw_keySize_max() { + return 512; + } + + @Override + @SuppressWarnings("MagicNumber") + public long mpw_otp_window() { + return 5 * 60 /* s */; + } + + @Override + @SuppressWarnings("MagicNumber") + public int scrypt_N() { + return 32768; + } + + @Override + @SuppressWarnings("MagicNumber") + public int scrypt_r() { + return 8; + } + + @Override + @SuppressWarnings("MagicNumber") + public int scrypt_p() { + return 2; + } + + // Utilities + + @Nonnull + public byte[] toBytes(final int number) { + return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number ).array(); + } + + @Nonnull + public byte[] toBytes(final UnsignedInteger number) { + return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number.intValue() ).array(); + } + + @Nonnull + public byte[] toBytes(final char[] characters) { + ByteBuffer byteBuffer = mpw_charset().encode( CharBuffer.wrap( characters ) ); + + byte[] bytes = new byte[byteBuffer.remaining()]; + byteBuffer.get( bytes ); + + Arrays.fill( byteBuffer.array(), (byte) 0 ); + return bytes; + } + + @Nonnull + public byte[] toID(final byte[] bytes) { + return mpw_hash().of( bytes ); + } } } diff --git a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java deleted file mode 100644 index 822b2f3c..00000000 --- a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java +++ /dev/null @@ -1,250 +0,0 @@ -//============================================================================== -// This file is part of Master Password. -// Copyright (c) 2011-2017, Maarten Billemont. -// -// Master Password is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Master Password is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You can find a copy of the GNU General Public License in the -// LICENSE file. Alternatively, see . -//============================================================================== - -package com.lyndir.masterpassword.impl; - -import com.google.common.base.Charsets; -import com.google.common.primitives.UnsignedInteger; -import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; -import com.lyndir.lhunath.opal.system.MessageDigests; -import com.lyndir.lhunath.opal.system.logging.Logger; -import com.lyndir.masterpassword.*; -import java.nio.*; -import java.nio.charset.*; -import java.util.Arrays; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - - -/** - * @author lhunath, 2014-08-30 - * @see MPAlgorithm.Version#V0 - */ -@SuppressWarnings("NewMethodNamingConvention") -public class MPAlgorithmV0 extends MPAlgorithm { - - @SuppressWarnings("HardcodedFileSeparator") - protected static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding"; - protected static final int AES_BLOCKSIZE = 128 /* bit */; - - static { - Native.load( MPAlgorithmV0.class, "mpw" ); - } - - protected final Logger logger = Logger.get( getClass() ); - - @Nullable - @Override - public byte[] masterKey(final String fullName, final char[] masterPassword) { - - // Create a memory-safe NUL-terminated UTF-8 C-string byte array variant of masterPassword. - CharsetEncoder encoder = mpw_charset().newEncoder(); - byte[] masterPasswordBytes = new byte[(int) (masterPassword.length * (double) encoder.maxBytesPerChar()) + 1]; - try { - Arrays.fill( masterPasswordBytes, (byte) 0 ); - ByteBuffer masterPasswordBuffer = ByteBuffer.wrap( masterPasswordBytes ); - - CoderResult result = encoder.encode( CharBuffer.wrap( masterPassword ), masterPasswordBuffer, true ); - if (result.isError()) - throw new IllegalStateException( result.toString() ); - result = encoder.flush( masterPasswordBuffer ); - if (result.isError()) - throw new IllegalStateException( result.toString() ); - - return _masterKey( fullName, masterPasswordBytes, version().toInt() ); - } - finally { - Arrays.fill( masterPasswordBytes, (byte) 0 ); - } - } - - @Nullable - protected native byte[] _masterKey(final String fullName, final byte[] masterPassword, final int algorithmVersion); - - @Nullable - @Override - public byte[] siteKey(final byte[] masterKey, final String siteName, final UnsignedInteger siteCounter, - final MPKeyPurpose keyPurpose, @Nullable final String keyContext) { - - return _siteKey( masterKey, siteName, siteCounter.longValue(), keyPurpose.toInt(), keyContext, version().toInt() ); - } - - @Nullable - protected native byte[] _siteKey(final byte[] masterKey, final String siteName, final long siteCounter, - final int keyPurpose, @Nullable final String keyContext, final int version); - - @Nullable - @Override - public String siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter, - final MPKeyPurpose keyPurpose, @Nullable final String keyContext, - final MPResultType resultType, @Nullable final String resultParam) { - - return _siteResult( masterKey, siteKey, siteName, siteCounter.longValue(), - keyPurpose.toInt(), keyContext, resultType.getType(), resultParam, version().toInt() ); - } - - @Nullable - protected native String _siteResult(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter, - final int keyPurpose, @Nullable final String keyContext, - final int resultType, @Nullable final String resultParam, final int algorithmVersion); - - @Nullable - @Override - public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter, - final MPKeyPurpose keyPurpose, @Nullable final String keyContext, - final MPResultType resultType, final String resultParam) { - - return _siteState( masterKey, siteKey, siteName, siteCounter.longValue(), - keyPurpose.toInt(), keyContext, resultType.getType(), resultParam, version().toInt() ); - } - - @Nullable - protected native String _siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final long siteCounter, - final int keyPurpose, @Nullable final String keyContext, - final int resultType, final String resultParam, final int algorithmVersion); - - // Configuration - - @Nonnull - @Override - public Version version() { - return MPAlgorithm.Version.V0; - } - - @Nonnull - @Override - public UnsignedInteger mpw_default_counter() { - return UnsignedInteger.ONE; - } - - @Nonnull - @Override - public MPResultType mpw_default_result_type() { - return MPResultType.GeneratedLong; - } - - @Nonnull - @Override - public MPResultType mpw_default_login_type() { - return MPResultType.GeneratedName; - } - - @Nonnull - @Override - public MPResultType mpw_default_answer_type() { - return MPResultType.GeneratedPhrase; - } - - @Nonnull - @Override - public Charset mpw_charset() { - return Charsets.UTF_8; - } - - @Nonnull - @Override - public ByteOrder mpw_byteOrder() { - return ByteOrder.BIG_ENDIAN; - } - - @Nonnull - @Override - public MessageDigests mpw_hash() { - return MessageDigests.SHA256; - } - - @Nonnull - @Override - public MessageAuthenticationDigests mpw_digest() { - return MessageAuthenticationDigests.HmacSHA256; - } - - @Override - @SuppressWarnings("MagicNumber") - public int mpw_dkLen() { - return 64; - } - - @Override - @SuppressWarnings("MagicNumber") - public int mpw_keySize_min() { - return 128; - } - - @Override - @SuppressWarnings("MagicNumber") - public int mpw_keySize_max() { - return 512; - } - - @Override - @SuppressWarnings("MagicNumber") - public long mpw_otp_window() { - return 5 * 60 /* s */; - } - - @Override - @SuppressWarnings("MagicNumber") - public int scrypt_N() { - return 32768; - } - - @Override - @SuppressWarnings("MagicNumber") - public int scrypt_r() { - return 8; - } - - @Override - @SuppressWarnings("MagicNumber") - public int scrypt_p() { - return 2; - } - - // Utilities - - @Nonnull - @Override - public byte[] toBytes(final int number) { - return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number ).array(); - } - - @Nonnull - @Override - public byte[] toBytes(final UnsignedInteger number) { - return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number.intValue() ).array(); - } - - @Nonnull - @Override - public byte[] toBytes(final char[] characters) { - ByteBuffer byteBuffer = mpw_charset().encode( CharBuffer.wrap( characters ) ); - - byte[] bytes = new byte[byteBuffer.remaining()]; - byteBuffer.get( bytes ); - - Arrays.fill( byteBuffer.array(), (byte) 0 ); - return bytes; - } - - @Nonnull - @Override - public byte[] toID(final byte[] bytes) { - return mpw_hash().of( bytes ); - } -} diff --git a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV1.java b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV1.java deleted file mode 100644 index 81c1a12b..00000000 --- a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV1.java +++ /dev/null @@ -1,38 +0,0 @@ -//============================================================================== -// This file is part of Master Password. -// Copyright (c) 2011-2017, Maarten Billemont. -// -// Master Password is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Master Password is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You can find a copy of the GNU General Public License in the -// LICENSE file. Alternatively, see . -//============================================================================== - -package com.lyndir.masterpassword.impl; - -import com.lyndir.masterpassword.*; -import javax.annotation.Nonnull; - - -/** - * @author lhunath, 2014-08-30 - * @see Version#V1 - */ -public class MPAlgorithmV1 extends MPAlgorithmV0 { - - // Configuration - - @Nonnull - @Override - public Version version() { - return MPAlgorithm.Version.V1; - } -} diff --git a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV2.java b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV2.java deleted file mode 100644 index dc6c77f0..00000000 --- a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV2.java +++ /dev/null @@ -1,38 +0,0 @@ -//============================================================================== -// This file is part of Master Password. -// Copyright (c) 2011-2017, Maarten Billemont. -// -// Master Password is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Master Password is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You can find a copy of the GNU General Public License in the -// LICENSE file. Alternatively, see . -//============================================================================== - -package com.lyndir.masterpassword.impl; - -import com.lyndir.masterpassword.MPAlgorithm; -import javax.annotation.Nonnull; - - -/** - * @author lhunath, 2014-08-30 - * @see Version#V2 - */ -public class MPAlgorithmV2 extends MPAlgorithmV1 { - - // Configuration - - @Nonnull - @Override - public Version version() { - return MPAlgorithm.Version.V2; - } -} diff --git a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV3.java b/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV3.java deleted file mode 100644 index 2891980e..00000000 --- a/platform-independent/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV3.java +++ /dev/null @@ -1,38 +0,0 @@ -//============================================================================== -// This file is part of Master Password. -// Copyright (c) 2011-2017, Maarten Billemont. -// -// Master Password is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Master Password is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You can find a copy of the GNU General Public License in the -// LICENSE file. Alternatively, see . -//============================================================================== - -package com.lyndir.masterpassword.impl; - -import com.lyndir.masterpassword.MPAlgorithm; -import javax.annotation.Nonnull; - - -/** - * @author lhunath, 2014-08-30 - * @see Version#V3 - */ -public class MPAlgorithmV3 extends MPAlgorithmV2 { - - // Configuration - - @Nonnull - @Override - public Version version() { - return MPAlgorithm.Version.V3; - } -} diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/model/MPIncognitoUser.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/model/MPIncognitoUser.java index 413e81d8..305b2caa 100755 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/model/MPIncognitoUser.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/model/MPIncognitoUser.java @@ -30,7 +30,7 @@ import javax.annotation.Nullable; public class MPIncognitoUser extends MPBasicUser { public MPIncognitoUser(final String fullName) { - super( fullName, MPAlgorithm.Version.CURRENT.getAlgorithm() ); + super( fullName, MPAlgorithm.Version.CURRENT ); } @Nullable diff --git a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java index b573eb66..6d948405 100644 --- a/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java +++ b/platform-independent/java/gui/src/main/java/com/lyndir/masterpassword/gui/view/UserContentPanel.java @@ -577,7 +577,7 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L components.add( Components.label( "Default Algorithm:" ), Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name, - user.getAlgorithm().version(), version -> user.setAlgorithm( version.getAlgorithm() ) ) ); + user.getAlgorithm().version(), user::setAlgorithm ) ); components.add( Components.label( "Default Password Type:" ), Components.comboBox( MPResultType.values(), MPResultType::getLongName, @@ -614,7 +614,7 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L components.add( Components.label( "Algorithm:" ), Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name, site.getAlgorithm().version(), - version -> site.setAlgorithm( version.getAlgorithm() ) ) ); + site::setAlgorithm ) ); components.add( Components.label( "Counter:" ), Components.spinner( new UnsignedIntegerModel( site.getCounter(), UnsignedInteger.ONE ) diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java index 94e0b249..76d97548 100755 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFileUser.java @@ -59,7 +59,7 @@ public class MPFileUser extends MPBasicUser { } public MPFileUser(final String fullName, final File location) { - this( fullName, null, MPAlgorithm.Version.CURRENT.getAlgorithm(), location ); + this( fullName, null, MPAlgorithm.Version.CURRENT, location ); } public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final File location) { diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java index 9d6e290f..673e9307 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPFlatUnmarshaller.java @@ -68,7 +68,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { else if ((fullName != null) && (keyID != null)) // Ends the header. return new MPFileUser( - fullName, keyID, MPAlgorithm.Version.fromInt( mpVersion ).getAlgorithm(), avatar, defaultType, + fullName, keyID, MPAlgorithm.Version.fromInt( mpVersion ), avatar, defaultType, date, false, clearContent? MPMarshaller.ContentMode.VISIBLE: MPMarshaller.ContentMode.PROTECTED, MPMarshalFormat.Flat, file ); @@ -157,7 +157,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { site = new MPFileSite( user, siteMatcher.group( 5 ), MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN( - colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(), + colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ), user.getAlgorithm().mpw_default_counter(), MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), clearContent? null: siteMatcher.group( 6 ), @@ -171,7 +171,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller { site = new MPFileSite( user, siteMatcher.group( 7 ), MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN( - colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(), + colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ), UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ), MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), diff --git a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java index 5cb3b85a..bbd38036 100644 --- a/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java +++ b/platform-independent/java/model/src/main/java/com/lyndir/masterpassword/model/impl/MPJSONFile.java @@ -128,7 +128,7 @@ public class MPJSONFile extends MPJSONAnyObject { } MPFileUser readUser(final File file) { - MPAlgorithm algorithm = ifNotNullElse( user.algorithm, MPAlgorithm.Version.CURRENT ).getAlgorithm(); + MPAlgorithm algorithm = ifNotNullElse( user.algorithm, MPAlgorithm.Version.CURRENT ); return new MPFileUser( user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar, @@ -146,7 +146,7 @@ public class MPJSONFile extends MPJSONAnyObject { String siteName = siteEntry.getKey(); Site fileSite = siteEntry.getValue(); MPFileSite site = new MPFileSite( - user, siteName, fileSite.algorithm.getAlgorithm(), UnsignedInteger.valueOf( fileSite.counter ), + user, siteName, fileSite.algorithm, UnsignedInteger.valueOf( fileSite.counter ), fileSite.type, export.redacted? fileSite.password: null, fileSite.login_type, export.redacted? fileSite.login_name: null, (fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses, diff --git a/platform-independent/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java b/platform-independent/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java index c486dfb6..0e6ad66d 100644 --- a/platform-independent/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java +++ b/platform-independent/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java @@ -191,7 +191,7 @@ public class MPTests { @Nonnull public MPAlgorithm getAlgorithm() { - return MPAlgorithm.Version.fromInt( checkNotNull( algorithm ) ).getAlgorithm(); + return MPAlgorithm.Version.fromInt( checkNotNull( algorithm ) ); } @Nonnull diff --git a/platform-independent/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java b/platform-independent/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java index ef692f49..14d6bdd1 100644 --- a/platform-independent/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java +++ b/platform-independent/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java @@ -106,9 +106,7 @@ public class MPMasterKeyTest { String password = randomString( 8 ); MPResultType resultType = MPResultType.StoredPersonal; - for (final MPAlgorithm.Version version : MPAlgorithm.Version.values()) { - MPAlgorithm algorithm = version.getAlgorithm(); - + for (final MPAlgorithm.Version algorithm : MPAlgorithm.Version.values()) { // Test site state String state = masterKey.siteState( testCase.getSiteName(), algorithm, testCase.getSiteCounter(), testCase.getKeyPurpose(), testCase.getKeyContext(), resultType, password );