2
0
Fork 0

Clean up now that implementation is Native only.

This commit is contained in:
Maarten Billemont 2019-10-23 09:25:57 -04:00
parent aec5e371b8
commit 023749049a
18 changed files with 314 additions and 481 deletions

View File

@ -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/base64.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/aes.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.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-types.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-util.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-util.c"
"${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal-util.c" "${PROJECT_SOURCE_DIR}/../platform-independent/c/core/src/mpw-marshal-util.c"

View File

@ -316,8 +316,8 @@ public class EmergencyActivity extends Activity {
@Override @Override
public void run() { public void run() {
try { try {
sitePassword = masterKey.siteResult( siteName, version.getAlgorithm(), counter, sitePassword = masterKey.siteResult(
MPKeyPurpose.Authentication, null, type, null ); siteName, version, counter, MPKeyPurpose.Authentication, null, type, null );
runOnUiThread( new Runnable() { runOnUiThread( new Runnable() {
@Override @Override

View File

@ -149,7 +149,7 @@ public final class Preferences {
@Nonnull @Nonnull
public MPResultType getDefaultResultType() { public MPResultType getDefaultResultType() {
return MPResultType.values()[ 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) { public boolean setDefaultVersion(final MPAlgorithm.Version value) {

View File

@ -0,0 +1,47 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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

View File

@ -1,47 +0,0 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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

View File

@ -1,6 +1,6 @@
#include <string.h> #include <string.h>
#include "java/com_lyndir_masterpassword_impl_MPAlgorithmV0.h" #include "java/com_lyndir_masterpassword_MPAlgorithm_Version.h"
#include "mpw-algorithm.h" #include "mpw-algorithm.h"
#include "mpw-util.h" #include "mpw-util.h"

View File

@ -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.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.base.Charsets;
import com.google.common.primitives.UnsignedInteger; import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.MessageDigests; import com.lyndir.lhunath.opal.system.MessageDigests;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.masterpassword.impl.*; import com.lyndir.masterpassword.impl.*;
import java.nio.ByteOrder; import java.nio.*;
import java.nio.charset.Charset; import java.nio.charset.*;
import java.util.Arrays;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -36,7 +39,7 @@ import javax.annotation.Nullable;
* @see Version * @see Version
*/ */
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" }) @SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" })
public abstract class MPAlgorithm { public interface MPAlgorithm {
/** /**
* Derive a master key that describes a user's identity. * 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. * @param masterPassword The user's secret that authenticates his access to the identity.
*/ */
@Nullable @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. * 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. * @param keyContext An action-specific context within which to scope the key.
*/ */
@Nullable @Nullable
public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter,
MPKeyPurpose keyPurpose, @Nullable String keyContext); MPKeyPurpose keyPurpose, @Nullable String keyContext);
/** /**
* Encode a templated result for a site key. * 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. * @param resultParam A parameter that provides contextual data specific to the type template.
*/ */
@Nullable @Nullable
public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
MPKeyPurpose keyPurpose, @Nullable String keyContext, MPKeyPurpose keyPurpose, @Nullable String keyContext,
MPResultType resultType, @Nullable String resultParam); MPResultType resultType, @Nullable String resultParam);
/** /**
* For {@link MPResultTypeClass#Stateful} {@code resultType}s, generate the {@code resultParam} to use with the * 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. * @param resultParam A parameter that provides contextual data specific to the type template.
*/ */
@Nullable @Nullable
public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter,
MPKeyPurpose keyPurpose, @Nullable String keyContext, MPKeyPurpose keyPurpose, @Nullable String keyContext,
MPResultType resultType, String resultParam); MPResultType resultType, String resultParam);
// Configuration // Configuration
@ -90,115 +93,105 @@ public abstract class MPAlgorithm {
* The linear version identifier of this algorithm's implementation. * The linear version identifier of this algorithm's implementation.
*/ */
@Nonnull @Nonnull
public abstract Version version(); Version version();
/** /**
* mpw: defaults: initial counter value. * mpw: defaults: initial counter value.
*/ */
@Nonnull @Nonnull
public abstract UnsignedInteger mpw_default_counter(); UnsignedInteger mpw_default_counter();
/** /**
* mpw: defaults: password result type. * mpw: defaults: password result type.
*/ */
@Nonnull @Nonnull
public abstract MPResultType mpw_default_result_type(); MPResultType mpw_default_result_type();
/** /**
* mpw: defaults: login result type. * mpw: defaults: login result type.
*/ */
@Nonnull @Nonnull
public abstract MPResultType mpw_default_login_type(); MPResultType mpw_default_login_type();
/** /**
* mpw: defaults: answer result type. * mpw: defaults: answer result type.
*/ */
@Nonnull @Nonnull
public abstract MPResultType mpw_default_answer_type(); MPResultType mpw_default_answer_type();
/** /**
* mpw: Input character encoding. * mpw: Input character encoding.
*/ */
@Nonnull @Nonnull
public abstract Charset mpw_charset(); Charset mpw_charset();
/** /**
* mpw: Platform-agnostic byte order. * mpw: Platform-agnostic byte order.
*/ */
@Nonnull @Nonnull
public abstract ByteOrder mpw_byteOrder(); ByteOrder mpw_byteOrder();
/** /**
* mpw: Key ID hash. * mpw: Key ID hash.
*/ */
@Nonnull @Nonnull
public abstract MessageDigests mpw_hash(); MessageDigests mpw_hash();
/** /**
* mpw: Site digest. * mpw: Site digest.
*/ */
@Nonnull @Nonnull
public abstract MessageAuthenticationDigests mpw_digest(); MessageAuthenticationDigests mpw_digest();
/** /**
* mpw: Master key size (byte). * mpw: Master key size (byte).
*/ */
public abstract int mpw_dkLen(); int mpw_dkLen();
/** /**
* mpw: Minimum size for derived keys (bit). * mpw: Minimum size for derived keys (bit).
*/ */
public abstract int mpw_keySize_min(); int mpw_keySize_min();
/** /**
* mpw: Maximum size for derived keys (bit). * 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). * mpw: validity for the time-based rolling counter (s).
*/ */
public abstract long mpw_otp_window(); long mpw_otp_window();
/** /**
* scrypt: CPU cost parameter. * scrypt: CPU cost parameter.
*/ */
public abstract int scrypt_N(); int scrypt_N();
/** /**
* scrypt: Memory cost parameter. * scrypt: Memory cost parameter.
*/ */
public abstract int scrypt_r(); int scrypt_r();
/** /**
* scrypt: Parallelization parameter. * scrypt: Parallelization parameter.
*/ */
public abstract int scrypt_p(); int scrypt_p();
// Utilities // Utilities
@Nonnull byte[] toBytes(final int number);
protected abstract byte[] toBytes(int number);
@Nonnull byte[] toBytes(final UnsignedInteger number);
protected abstract byte[] toBytes(UnsignedInteger number);
@Nonnull byte[] toBytes(final char[] characters);
protected abstract byte[] toBytes(char[] characters);
@Nonnull byte[] toID(final byte[] bytes);
protected abstract byte[] toID(byte[] bytes);
@Override
public String toString() {
return strf( "%d, %s", version().toInt(), getClass().getSimpleName() );
}
/** /**
* The algorithm iterations. * The algorithm iterations.
*/ */
public enum Version { enum Version implements MPAlgorithm {
/** /**
* bugs: * 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 site names.
* - miscounted the byte-length for multi-byte user names. * - miscounted the byte-length for multi-byte user names.
*/ */
V0( new MPAlgorithmV0() ), V0,
/** /**
* bugs: * bugs:
* - miscounted the byte-length for multi-byte site names. * - miscounted the byte-length for multi-byte site names.
* - miscounted the byte-length for multi-byte user names. * - miscounted the byte-length for multi-byte user names.
*/ */
V1( new MPAlgorithmV1() ), V1,
/** /**
* bugs: * bugs:
* - miscounted the byte-length for multi-byte user names. * - miscounted the byte-length for multi-byte user names.
*/ */
V2( new MPAlgorithmV2() ), V2,
/** /**
* bugs: * bugs:
* - no known issues. * - no known issues.
*/ */
V3( new MPAlgorithmV3() ); V3;
public static final Version CURRENT = 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) { static {
this.algorithm = algorithm; Native.load( MPAlgorithm.class, "mpw" );
} }
public MPAlgorithm getAlgorithm() { protected final Logger logger = Logger.get( getClass() );
return algorithm;
}
@JsonCreator @JsonCreator
public static Version fromInt(final int algorithmVersion) { public static Version fromInt(final int algorithmVersion) {
@ -250,5 +243,207 @@ public abstract class MPAlgorithm {
return ordinal(); 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 );
}
} }
} }

View File

@ -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 <http://www.gnu.org/licenses/>.
//==============================================================================
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 );
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//==============================================================================
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//==============================================================================
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
//==============================================================================
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;
}
}

View File

@ -30,7 +30,7 @@ import javax.annotation.Nullable;
public class MPIncognitoUser extends MPBasicUser<MPIncognitoSite> { public class MPIncognitoUser extends MPBasicUser<MPIncognitoSite> {
public MPIncognitoUser(final String fullName) { public MPIncognitoUser(final String fullName) {
super( fullName, MPAlgorithm.Version.CURRENT.getAlgorithm() ); super( fullName, MPAlgorithm.Version.CURRENT );
} }
@Nullable @Nullable

View File

@ -577,7 +577,7 @@ public class UserContentPanel extends JPanel implements State.Listener, MPUser.L
components.add( Components.label( "Default Algorithm:" ), components.add( Components.label( "Default Algorithm:" ),
Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name, 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.add( Components.label( "Default Password Type:" ),
Components.comboBox( MPResultType.values(), MPResultType::getLongName, 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.add( Components.label( "Algorithm:" ),
Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name, Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name,
site.getAlgorithm().version(), site.getAlgorithm().version(),
version -> site.setAlgorithm( version.getAlgorithm() ) ) ); site::setAlgorithm ) );
components.add( Components.label( "Counter:" ), components.add( Components.label( "Counter:" ),
Components.spinner( new UnsignedIntegerModel( site.getCounter(), UnsignedInteger.ONE ) Components.spinner( new UnsignedIntegerModel( site.getCounter(), UnsignedInteger.ONE )

View File

@ -59,7 +59,7 @@ public class MPFileUser extends MPBasicUser<MPFileSite> {
} }
public MPFileUser(final String fullName, final File location) { 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) { public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final File location) {

View File

@ -68,7 +68,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
else if ((fullName != null) && (keyID != null)) else if ((fullName != null) && (keyID != null))
// Ends the header. // Ends the header.
return new MPFileUser( 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, date, false, clearContent? MPMarshaller.ContentMode.VISIBLE: MPMarshaller.ContentMode.PROTECTED,
MPMarshalFormat.Flat, file MPMarshalFormat.Flat, file
); );
@ -157,7 +157,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
site = new MPFileSite( site = new MPFileSite(
user, siteMatcher.group( 5 ), user, siteMatcher.group( 5 ),
MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN( MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(), colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
user.getAlgorithm().mpw_default_counter(), user.getAlgorithm().mpw_default_counter(),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
clearContent? null: siteMatcher.group( 6 ), clearContent? null: siteMatcher.group( 6 ),
@ -171,7 +171,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
site = new MPFileSite( site = new MPFileSite(
user, siteMatcher.group( 7 ), user, siteMatcher.group( 7 ),
MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN( MPAlgorithm.Version.fromInt( ConversionUtils.toIntegerNN(
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(), colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
UnsignedInteger.valueOf( UnsignedInteger.valueOf(
colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ), colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ), MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),

View File

@ -128,7 +128,7 @@ public class MPJSONFile extends MPJSONAnyObject {
} }
MPFileUser readUser(final File file) { 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( return new MPFileUser(
user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar, user.full_name, CodeUtils.decodeHex( user.key_id ), algorithm, user.avatar,
@ -146,7 +146,7 @@ public class MPJSONFile extends MPJSONAnyObject {
String siteName = siteEntry.getKey(); String siteName = siteEntry.getKey();
Site fileSite = siteEntry.getValue(); Site fileSite = siteEntry.getValue();
MPFileSite site = new MPFileSite( 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.type, export.redacted? fileSite.password: null,
fileSite.login_type, export.redacted? fileSite.login_name: null, fileSite.login_type, export.redacted? fileSite.login_name: null,
(fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses, (fileSite._ext_mpw != null)? fileSite._ext_mpw.url: null, fileSite.uses,

View File

@ -191,7 +191,7 @@ public class MPTests {
@Nonnull @Nonnull
public MPAlgorithm getAlgorithm() { public MPAlgorithm getAlgorithm() {
return MPAlgorithm.Version.fromInt( checkNotNull( algorithm ) ).getAlgorithm(); return MPAlgorithm.Version.fromInt( checkNotNull( algorithm ) );
} }
@Nonnull @Nonnull

View File

@ -106,9 +106,7 @@ public class MPMasterKeyTest {
String password = randomString( 8 ); String password = randomString( 8 );
MPResultType resultType = MPResultType.StoredPersonal; MPResultType resultType = MPResultType.StoredPersonal;
for (final MPAlgorithm.Version version : MPAlgorithm.Version.values()) { for (final MPAlgorithm.Version algorithm : MPAlgorithm.Version.values()) {
MPAlgorithm algorithm = version.getAlgorithm();
// Test site state // Test site state
String state = masterKey.siteState( testCase.getSiteName(), algorithm, testCase.getSiteCounter(), testCase.getKeyPurpose(), String state = masterKey.siteState( testCase.getSiteName(), algorithm, testCase.getSiteCounter(), testCase.getKeyPurpose(),
testCase.getKeyContext(), resultType, password ); testCase.getKeyContext(), resultType, password );