2
0

Java relocation.

This commit is contained in:
Maarten Billemont
2018-06-05 20:19:10 -04:00
parent aef8422102
commit 190a241a25
57 changed files with 5 additions and 5 deletions

View File

@@ -0,0 +1,39 @@
plugins {
id 'java-library'
}
description = 'Master Password Algorithm Implementation'
configurations {
lib
}
dependencies {
implementation group: 'com.lyndir.lhunath.opal', name: 'opal-system', version: '1.7-p1'
api group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.9.5'
api group: 'org.jetbrains', name: 'annotations', version: '13.0'
api group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
api group: 'com.google.code.findbugs', name: 'findbugs-annotations', version: '3.0.1'
lib project( path: ':masterpassword-core', configuration: 'default' )
}
processResources {
dependsOn task( type: Sync, 'copyResources', {
dependsOn configurations.lib {
files.each { libFile ->
from zipTree( libFile )
into new File( processResources.outputs.files.singleFile, "lib" )
}
}
} )
}
compileJava {
doLast {
ant.javah( class: 'com.lyndir.masterpassword.impl.MPAlgorithmV0',
outputFile: '../../c/src/mpw-jni.h',
classpath: files( sourceSets.main.compileClasspath, sourceSets.main.output ).asPath )
}
}

View File

@@ -0,0 +1,240 @@
//==============================================================================
// 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;
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.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.MessageDigests;
import com.lyndir.masterpassword.impl.*;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import javax.annotation.Nullable;
/**
* @see Version
*/
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention", "MethodReturnAlwaysConstant" })
public abstract class MPAlgorithm {
/**
* Derive a master key that describes a user's identity.
*
* @param fullName The name of the user whose identity is described by the key.
* @param masterPassword The user's secret that authenticates his access to the identity.
*/
@Nullable
public abstract byte[] masterKey(String fullName, char[] masterPassword);
/**
* Derive a site key that describes a user's access to a specific entity.
*
* @param masterKey The identity of the user trying to access the entity.
* @param siteName The name of the entity to access.
* @param siteCounter The site key's generation.
* @param keyPurpose The action that the user aims to undertake with this key.
* @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);
/**
* Encode a templated result for a site key.
*
* @param resultType The template to base the site key's encoding on.
* @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);
/**
* For {@link MPResultTypeClass#Stateful} {@code resultType}s, generate the {@code resultParam} to use with the
* {@link #siteResult(byte[], byte[], String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)} call
* in order to reconstruct this call's original {@code resultParam}.
*
* @param resultType The template to base the site key's encoding on.
* @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);
// Configuration
/**
* The linear version identifier of this algorithm's implementation.
*/
public abstract Version version();
/**
* mpw: defaults: initial counter value.
*/
public abstract UnsignedInteger mpw_default_counter();
/**
* mpw: defaults: password result type.
*/
public abstract MPResultType mpw_default_result_type();
/**
* mpw: defaults: login result type.
*/
public abstract MPResultType mpw_default_login_type();
/**
* mpw: defaults: answer result type.
*/
public abstract MPResultType mpw_default_answer_type();
/**
* mpw: Input character encoding.
*/
public abstract Charset mpw_charset();
/**
* mpw: Platform-agnostic byte order.
*/
public abstract ByteOrder mpw_byteOrder();
/**
* mpw: Key ID hash.
*/
public abstract MessageDigests mpw_hash();
/**
* mpw: Site digest.
*/
public abstract MessageAuthenticationDigests mpw_digest();
/**
* mpw: Master key size (byte).
*/
public abstract int mpw_dkLen();
/**
* mpw: Minimum size for derived keys (bit).
*/
public abstract int mpw_keySize_min();
/**
* mpw: Maximum size for derived keys (bit).
*/
public abstract int mpw_keySize_max();
/**
* mpw: validity for the time-based rolling counter (s).
*/
public abstract long mpw_otp_window();
/**
* scrypt: CPU cost parameter.
*/
public abstract int scrypt_N();
/**
* scrypt: Memory cost parameter.
*/
public abstract int scrypt_r();
/**
* scrypt: Parallelization parameter.
*/
public abstract int scrypt_p();
// Utilities
protected abstract byte[] toBytes(int number);
protected abstract byte[] toBytes(UnsignedInteger number);
protected abstract byte[] toBytes(char[] characters);
protected abstract byte[] toID(byte[] bytes);
@Override
public String toString() {
return strf( "%d, %s", version().toInt(), getClass().getSimpleName() );
}
/**
* The algorithm iterations.
*/
public enum Version {
/**
* bugs:
* - does math with chars whose signedness was platform-dependent.
* - miscounted the byte-length for multi-byte site names.
* - miscounted the byte-length for multi-byte user names.
*/
V0( new MPAlgorithmV0() ),
/**
* bugs:
* - miscounted the byte-length for multi-byte site names.
* - miscounted the byte-length for multi-byte user names.
*/
V1( new MPAlgorithmV1() ),
/**
* bugs:
* - miscounted the byte-length for multi-byte user names.
*/
V2( new MPAlgorithmV2() ),
/**
* bugs:
* - no known issues.
*/
V3( new MPAlgorithmV3() );
public static final Version CURRENT = V3;
private final MPAlgorithm algorithm;
Version(final MPAlgorithm algorithm) {
this.algorithm = algorithm;
}
public MPAlgorithm getAlgorithm() {
return algorithm;
}
@JsonCreator
public static Version fromInt(final int algorithmVersion) {
return values()[algorithmVersion];
}
@JsonValue
public int toInt() {
return ordinal();
}
}
}

View File

@@ -0,0 +1,33 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2017-09-21
*/
public class MPAlgorithmException extends MPException {
public MPAlgorithmException(final String message) {
super( message );
}
public MPAlgorithmException(final String message, final Throwable cause) {
super( message, cause );
}
}

View File

@@ -0,0 +1,33 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2018-06-03
*/
public class MPException extends Exception {
public MPException(final String message) {
super( message );
}
public MPException(final String message, final Throwable cause) {
super( message, cause );
}
}

View File

@@ -0,0 +1,99 @@
//==============================================================================
// 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;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Charsets;
import com.google.common.primitives.UnsignedBytes;
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.nio.*;
import java.nio.charset.Charset;
import java.util.Arrays;
/**
* @author lhunath, 15-03-29
*/
public class MPIdenticon {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPIdenticon.class );
private static final Charset charset = Charsets.UTF_8;
private static final Color[] colors = {
Color.RED, Color.GREEN, Color.YELLOW, Color.BLUE, Color.MAGENTA, Color.CYAN, Color.MONO };
private static final char[] leftArm = { '╔', '╚', '╰', '═' };
private static final char[] rightArm = { '╗', '╝', '╯', '═' };
private static final char[] body = { '█', '░', '▒', '▓', '☺', '☻' };
private static final char[] accessory = {
'◈', '◎', '◐', '◑', '◒', '◓', '☀', '☁', '☂', '☃', '☄', '★', '☆', '☎', '☏', '⎈', '⌂', '☘', '☢', '☣', '☕', '⌚', '⌛', '⏰', '⚡',
'⛄', '⛅', '☔', '♔', '♕', '♖', '♗', '♘', '♙', '♚', '♛', '♜', '♝', '♞', '♟', '♨', '♩', '♪', '♫', '⚐', '⚑', '⚔', '⚖', '⚙', '⚠',
'⌘', '⏎', '✄', '✆', '✈', '✉', '✌' };
private final String fullName;
private final Color color;
private final String text;
public MPIdenticon(final String fullName, final String masterPassword) {
this( fullName, masterPassword.toCharArray() );
}
@SuppressWarnings("MethodCanBeVariableArityMethod")
public MPIdenticon(final String fullName, final char[] masterPassword) {
this.fullName = fullName;
byte[] masterPasswordBytes = charset.encode( CharBuffer.wrap( masterPassword ) ).array();
ByteBuffer identiconSeedBytes = ByteBuffer.wrap(
MessageAuthenticationDigests.HmacSHA256.of( masterPasswordBytes, fullName.getBytes( charset ) ) );
Arrays.fill( masterPasswordBytes, (byte) 0 );
IntBuffer identiconSeedBuffer = IntBuffer.allocate( identiconSeedBytes.capacity() );
while (identiconSeedBytes.hasRemaining())
identiconSeedBuffer.put( UnsignedBytes.toInt( identiconSeedBytes.get() ) );
int[] identiconSeed = identiconSeedBuffer.array();
color = colors[identiconSeed[4] % colors.length];
text = strf( "%c%c%c%c", leftArm[identiconSeed[0] % leftArm.length], body[identiconSeed[1] % body.length],
rightArm[identiconSeed[2] % rightArm.length], accessory[identiconSeed[3] % accessory.length] );
}
public String getFullName() {
return fullName;
}
public String getText() {
return text;
}
public Color getColor() {
return color;
}
public enum Color {
RED,
GREEN,
YELLOW,
BLUE,
MAGENTA,
CYAN,
MONO
}
}

View File

@@ -0,0 +1,103 @@
//==============================================================================
// 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;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Locale;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
/**
* @author lhunath, 14-12-02
*/
public enum MPKeyPurpose {
/**
* Generate a key for authentication.
*/
Authentication( "authentication", "Generate a key for authentication.", "com.lyndir.masterpassword" ),
/**
* Generate a name for identification.
*/
Identification( "identification", "Generate a name for identification.", "com.lyndir.masterpassword.login" ),
/**
* Generate a recovery token.
*/
Recovery( "recovery", "Generate a recovery token.", "com.lyndir.masterpassword.answer" );
static final Logger logger = Logger.get( MPResultType.class );
private final String shortName;
private final String description;
private final String scope;
MPKeyPurpose(final String shortName, final String description, @NonNls final String scope) {
this.shortName = shortName;
this.description = description;
this.scope = scope;
}
public String getShortName() {
return shortName;
}
public String getDescription() {
return description;
}
public String getScope() {
return scope;
}
/**
* @param shortNamePrefix The name for the purpose to look up. It is a case insensitive prefix of the purpose's short name.
*
* @return The purpose registered with the given name.
*/
@Nullable
@Contract("!null -> !null")
public static MPKeyPurpose forName(@Nullable final String shortNamePrefix) {
if (shortNamePrefix == null)
return null;
for (final MPKeyPurpose type : values())
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
return type;
throw logger.bug( "No purpose for name: %s", shortNamePrefix );
}
@JsonCreator
public static MPKeyPurpose forInt(final int keyPurpose) {
return values()[keyPurpose];
}
@JsonValue
public int toInt() {
return ordinal();
}
}

View File

@@ -0,0 +1,33 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2017-09-21
*/
public class MPKeyUnavailableException extends MPException {
public MPKeyUnavailableException(final String message) {
super( message );
}
public MPKeyUnavailableException(final String message, final Throwable cause) {
super( message, cause );
}
}

View File

@@ -0,0 +1,196 @@
//==============================================================================
// 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;
import com.google.common.base.Preconditions;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.Arrays;
import java.util.EnumMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* @author lhunath, 2014-08-30
*/
public class MPMasterKey {
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPMasterKey.class );
private final EnumMap<MPAlgorithm.Version, byte[]> keyByVersion = new EnumMap<>( MPAlgorithm.Version.class );
private final String fullName;
private final char[] masterPassword;
private boolean invalidated;
/**
* @param masterPassword The characters of the user's master password.
* <b>Note: this method destroys the contents of the array.</b>
*/
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
public MPMasterKey(final String fullName, final char[] masterPassword) {
this.fullName = fullName;
this.masterPassword = masterPassword.clone();
Arrays.fill( masterPassword, (char) 0 );
}
@Nonnull
public String getFullName() {
return fullName;
}
/**
* Calculate an identifier for the master key.
*
* @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public byte[] getKeyID(final MPAlgorithm algorithm)
throws MPKeyUnavailableException, MPAlgorithmException {
return algorithm.toID( masterKey( algorithm ) );
}
/**
* Wipe this key's secrets from memory, making the object permanently unusable.
*/
public void invalidate() {
invalidated = true;
for (final byte[] key : keyByVersion.values())
Arrays.fill( key, (byte) 0 );
Arrays.fill( masterPassword, (char) 0 );
}
private byte[] masterKey(final MPAlgorithm algorithm)
throws MPKeyUnavailableException, MPAlgorithmException {
Preconditions.checkArgument( masterPassword.length > 0 );
if (invalidated)
throw new MPKeyUnavailableException( "Master key was invalidated." );
byte[] masterKey = keyByVersion.get( algorithm.version() );
if (masterKey == null) {
logger.trc( "-- mpw_masterKey (algorithm: %s)", algorithm );
logger.trc( "fullName: %s", fullName );
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex(
algorithm.toID( algorithm.toBytes( masterPassword ) ) ) );
keyByVersion.put( algorithm.version(), masterKey = algorithm.masterKey( fullName, masterPassword ) );
}
if (masterKey == null)
throw new MPAlgorithmException( "Could not derive master key." );
return masterKey;
}
private byte[] siteKey(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose, @Nullable final String keyContext)
throws MPKeyUnavailableException, MPAlgorithmException {
Preconditions.checkArgument( !siteName.isEmpty() );
byte[] masterKey = masterKey( algorithm );
logger.trc( "-- mpw_siteKey (algorithm: %s)", algorithm );
logger.trc( "siteName: %s", siteName );
logger.trc( "siteCounter: %s", siteCounter );
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
logger.trc( "keyContext: %s", keyContext );
byte[] siteKey = algorithm.siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
if (siteKey == null)
throw new MPAlgorithmException( "Could not derive site key." );
return siteKey;
}
/**
* Generate a token for use with site.
*
* @param siteName The site's identifier.
* @param siteCounter The result's generation.
* @param keyPurpose The intended purpose for the site token.
* @param keyContext The purpose-specific context for this token.
* @param resultType The type of token we're deriving.
* @param resultParam Type-specific contextual data for the derivation.
* In the case of {@link MPResultTypeClass#Stateful} types, the result of
* {@link #siteState(String, MPAlgorithm, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
*
* @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public String siteResult(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
final MPResultType resultType, @Nullable final String resultParam)
throws MPKeyUnavailableException, MPAlgorithmException {
byte[] masterKey = masterKey( algorithm );
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
logger.trc( "-- mpw_siteResult (algorithm: %s)", algorithm );
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
logger.trc( "resultParam: %s", resultParam );
String siteResult = algorithm.siteResult(
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
if (siteResult == null)
throw new MPAlgorithmException( "Could not derive site result." );
return siteResult;
}
/**
* Encrypt a stateful site token for persistence.
*
* @param siteName The site's identifier.
* @param siteCounter The result's generation.
* @param keyPurpose The intended purpose for the site token.
* @param keyContext The purpose-specific context for this token.
* @param resultType The type of token we're deriving.
* @param resultParam The original token that this method's state should reconstruct when passed into
* {@link #siteResult(String, MPAlgorithm, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
*
* @throws MPKeyUnavailableException {@link #invalidate()} has been called on this object.
*/
public String siteState(final String siteName, final MPAlgorithm algorithm, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
final MPResultType resultType, final String resultParam)
throws MPKeyUnavailableException, MPAlgorithmException {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
byte[] masterKey = masterKey( algorithm );
byte[] siteKey = siteKey( siteName, algorithm, siteCounter, keyPurpose, keyContext );
logger.trc( "-- mpw_siteState (algorithm: %s)", algorithm );
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( algorithm.mpw_charset() ).length, resultParam );
String siteState = algorithm.siteState(
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
if (siteState == null)
throw new MPAlgorithmException( "Could not derive site state." );
return siteState;
}
}

View File

@@ -0,0 +1,263 @@
//==============================================================================
// 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;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
import org.jetbrains.annotations.Contract;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
@SuppressWarnings({ "RedundantTypeArguments", "SpellCheckingInspection" })
public enum MPResultType {
// bit 0-3 | MPResultTypeClass | MPSiteFeature
/**
* 16: pg^VMAUBk5x3p%HP%i4=
*/
GeneratedMaximum( "maximum", "20 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ),
new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPResultTypeClass.Template, 0x0 ),
/**
* 17: BiroYena8:Kixa
*/
GeneratedLong( "long", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
new MPTemplate( "CvcvnoCvccCvcv" ), new MPTemplate( "CvcvCvccnoCvcv" ),
new MPTemplate( "CvcvCvccCvcvno" ), new MPTemplate( "CvcvnoCvcvCvcc" ),
new MPTemplate( "CvcvCvcvnoCvcc" ), new MPTemplate( "CvcvCvcvCvccno" ),
new MPTemplate( "CvccnoCvccCvcv" ), new MPTemplate( "CvccCvccnoCvcv" ),
new MPTemplate( "CvccCvccCvcvno" ), new MPTemplate( "CvcvnoCvccCvcc" ),
new MPTemplate( "CvcvCvccnoCvcc" ), new MPTemplate( "CvcvCvccCvccno" ),
new MPTemplate( "CvccnoCvcvCvcc" ), new MPTemplate( "CvccCvcvnoCvcc" ),
new MPTemplate( "CvccCvcvCvccno" ) ), //
MPResultTypeClass.Template, 0x1 ),
/**
* 18: BirSuj0-
*/
GeneratedMedium( "medium", "Copy-friendly, 8 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcnoCvc" ),
new MPTemplate( "CvcCvcno" ) ), //
MPResultTypeClass.Template, 0x2 ),
/**
* 19: Bir8
*/
GeneratedShort( "short", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPResultTypeClass.Template, 0x3 ),
/**
* 20: pO98MoD0
*/
GeneratedBasic( "basic", "8 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "aaanaaan" ),
new MPTemplate( "aannaaan" ),
new MPTemplate( "aaannaaa" ) ), //
MPResultTypeClass.Template, 0x4 ),
/**
* 21: 2798
*/
GeneratedPIN( "pin", "4 numbers.", //
ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPResultTypeClass.Template, 0x5 ),
/**
* 30: birsujano
*/
GeneratedName( "name", "9 letter name.", //
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPResultTypeClass.Template, 0xE ),
/**
* 31: bir yennoquce fefi
*/
GeneratedPhrase( "phrase", "20 character sentence.", //
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
MPResultTypeClass.Template, 0xF ),
/**
* 1056: Custom saved password.
*/
StoredPersonal( "personal", "AES-encrypted, exportable.", //
ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ),
/**
* 2081: Custom saved password that should not be exported from the device.
*/
StoredDevicePrivate( "device", "AES-encrypted, not exported.", //
ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ),
/**
* 4160: Derive a unique binary key.
*/
DeriveKey( "key", "Encryption key.", //
ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
static final Logger logger = Logger.get( MPResultType.class );
private final String shortName;
private final String description;
private final List<MPTemplate> templates;
private final MPResultTypeClass typeClass;
private final int typeIndex;
private final ImmutableSet<MPSiteFeature> typeFeatures;
MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
this.shortName = shortName;
this.description = description;
this.templates = templates;
this.typeClass = typeClass;
this.typeIndex = typeIndex;
ImmutableSet.Builder<MPSiteFeature> typeFeaturesBuilder = ImmutableSet.builder();
for (final MPSiteFeature typeFeature : typeFeatures) {
typeFeaturesBuilder.add( typeFeature );
}
this.typeFeatures = typeFeaturesBuilder.build();
}
public String getShortName() {
return shortName;
}
public String getDescription() {
return description;
}
public MPResultTypeClass getTypeClass() {
return typeClass;
}
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */)
public ImmutableSet<MPSiteFeature> getTypeFeatures() {
return typeFeatures;
}
public boolean supportsTypeFeature(final MPSiteFeature feature) {
return typeFeatures.contains( feature );
}
@JsonValue
public int getType() {
int mask = typeIndex | typeClass.getMask();
for (final MPSiteFeature typeFeature : typeFeatures)
mask |= typeFeature.getMask();
return mask;
}
/**
* @param shortNamePrefix The name for the type to look up. It is a case insensitive prefix of the type's short name.
*
* @return The type registered with the given name.
*/
@Nullable
@Contract("!null -> !null")
public static MPResultType forName(@Nullable final String shortNamePrefix) {
if (shortNamePrefix == null)
return null;
for (final MPResultType type : values())
if (type.getShortName().toLowerCase( Locale.ROOT ).startsWith( shortNamePrefix.toLowerCase( Locale.ROOT ) ))
return type;
throw logger.bug( "No type for name: %s", shortNamePrefix );
}
/**
* @param typeClass The class for which we look up types.
*
* @return All types that support the given class.
*/
public static ImmutableList<MPResultType> forClass(final MPResultTypeClass typeClass) {
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
for (final MPResultType type : values())
if (type.getTypeClass() == typeClass)
types.add( type );
return types.build();
}
/**
* @param type The type for which we look up types.
*
* @return The type registered with the given type.
*/
@JsonCreator
public static MPResultType forType(final int type) {
for (final MPResultType resultType : values())
if (resultType.getType() == type)
return resultType;
throw logger.bug( "No type: %s", type );
}
/**
* @param mask The type mask for which we look up types.
*
* @return All types that support the given mask's class & features.
*/
@SuppressWarnings({ "MagicNumber", "UnnecessaryParentheses" /* IDEA-191040 */ })
public static ImmutableList<MPResultType> forMask(final int mask) {
int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
ImmutableList.Builder<MPResultType> types = ImmutableList.builder();
for (final MPResultType resultType : values())
if (((resultType.getType() & ~0xF) & typeMask) != 0)
types.add( resultType );
return types.build();
}
public MPTemplate getTemplateAtRollingIndex(final int templateIndex) {
return templates.get( templateIndex % templates.size() );
}
}

View File

@@ -0,0 +1,51 @@
//==============================================================================
// 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;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPResultTypeClass {
// bit 4 - 9
/**
* Use the site key to generate a password from a template.
*/
Template( 1 << 4 ),
/**
* Use the site key to encrypt and decrypt a stateful entity.
*/
Stateful( 1 << 5 ),
/**
* Use the site key to derive a site-specific object.
*/
Derive( 1 << 6 );
private final int mask;
MPResultTypeClass(final int mask) {
this.mask = mask;
}
public int getMask() {
return mask;
}
}

View File

@@ -0,0 +1,53 @@
//==============================================================================
// 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;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public enum MPSiteFeature {
// bit 10 - 15
/**
* Export the key-protected content data.
*/
ExportContent( 1 << 10 ),
/**
* Never export content.
*/
DevicePrivate( 1 << 11 ),
/**
* Don't use this as the primary authentication result type.
*/
Alternative( 1 << 12 );
MPSiteFeature(final int mask) {
this.mask = mask;
}
private final int mask;
public int getMask() {
return mask;
}
}

View File

@@ -0,0 +1,70 @@
//==============================================================================
// 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;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.ImmutableList;
import com.lyndir.lhunath.opal.system.util.MetaObject;
import java.io.Serializable;
import java.util.List;
import org.jetbrains.annotations.NonNls;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
public class MPTemplate extends MetaObject implements Serializable {
private static final long serialVersionUID = 1L;
private final String templateString;
private final List<MPTemplateCharacterClass> template;
MPTemplate(@NonNls final String templateString) {
ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.builder();
for (int i = 0; i < templateString.length(); ++i)
builder.add( MPTemplateCharacterClass.forIdentifier( templateString.charAt( i ) ) );
this.templateString = templateString;
template = builder.build();
}
public String getTemplateString() {
return templateString;
}
public MPTemplateCharacterClass getCharacterClassAtIndex(final int index) {
return template.get( index );
}
public int length() {
return template.size();
}
@Override
public String toString() {
return strf( "{MPTemplate: %s}", templateString );
}
}

View File

@@ -0,0 +1,73 @@
//==============================================================================
// 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;
import com.lyndir.lhunath.opal.system.logging.Logger;
import org.jetbrains.annotations.NonNls;
/**
* <i>07 04, 2012</i>
*
* @author lhunath
*/
@SuppressWarnings({ "HardcodedFileSeparator", "SpellCheckingInspection" })
public enum MPTemplateCharacterClass {
UpperVowel( 'V', "AEIOU" ),
UpperConsonant( 'C', "BCDFGHJKLMNPQRSTVWXYZ" ),
LowerVowel( 'v', "aeiou" ),
LowerConsonant( 'c', "bcdfghjklmnpqrstvwxyz" ),
UpperAlphanumeric( 'A', "AEIOUBCDFGHJKLMNPQRSTVWXYZ" ),
Alphanumeric( 'a', "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz" ),
Numeric( 'n', "0123456789" ),
Other( 'o', "@&%?,=[]_:-+*$#!'^~;()/." ),
Any( 'x', "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()" ),
Space( ' ', " " );
@SuppressWarnings("UnusedDeclaration")
private static final Logger logger = Logger.get( MPTemplateCharacterClass.class );
private final char identifier;
private final char[] characters;
MPTemplateCharacterClass(final char identifier, @NonNls final String characters) {
this.identifier = identifier;
this.characters = characters.toCharArray();
}
public char getIdentifier() {
return identifier;
}
public char getCharacterAtRollingIndex(final int index) {
return characters[index % characters.length];
}
public static MPTemplateCharacterClass forIdentifier(final char identifier) {
for (final MPTemplateCharacterClass characterClass : values())
if (characterClass.getIdentifier() == identifier)
return characterClass;
throw logger.bug( "No character class defined for identifier: %s", identifier );
}
}

View File

@@ -0,0 +1,241 @@
//==============================================================================
// 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.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, "masterpassword-core" );
}
public final Version version = MPAlgorithm.Version.V0;
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.isUnderflow())
result.throwException();
result = encoder.flush( masterPasswordBuffer );
if (!result.isUnderflow())
result.throwException();
return _masterKey( fullName, masterPasswordBytes, version().toInt() );
}
catch (final CharacterCodingException e) {
throw new IllegalStateException( e );
}
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
@Override
public Version version() {
return MPAlgorithm.Version.V0;
}
@Override
public UnsignedInteger mpw_default_counter() {
return UnsignedInteger.ONE;
}
@Override
public MPResultType mpw_default_result_type() {
return MPResultType.GeneratedLong;
}
@Override
public MPResultType mpw_default_login_type() {
return MPResultType.GeneratedName;
}
@Override
public MPResultType mpw_default_answer_type() {
return MPResultType.GeneratedPhrase;
}
@Override
public Charset mpw_charset() {
return Charsets.UTF_8;
}
@Override
public ByteOrder mpw_byteOrder() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public MessageDigests mpw_hash() {
return MessageDigests.SHA256;
}
@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
@Override
public byte[] toBytes(final int number) {
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number ).array();
}
@Override
public byte[] toBytes(final UnsignedInteger number) {
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number.intValue() ).array();
}
@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;
}
@Override
public byte[] toID(final byte[] bytes) {
return mpw_hash().of( bytes );
}
}

View File

@@ -0,0 +1,36 @@
//==============================================================================
// 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.*;
/**
* @author lhunath, 2014-08-30
* @see Version#V1
*/
public class MPAlgorithmV1 extends MPAlgorithmV0 {
// Configuration
@Override
public Version version() {
return MPAlgorithm.Version.V1;
}
}

View File

@@ -0,0 +1,36 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2014-08-30
* @see Version#V2
*/
public class MPAlgorithmV2 extends MPAlgorithmV1 {
// Configuration
@Override
public Version version() {
return MPAlgorithm.Version.V2;
}
}

View File

@@ -0,0 +1,36 @@
//==============================================================================
// 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;
/**
* @author lhunath, 2014-08-30
* @see Version#V3
*/
public class MPAlgorithmV3 extends MPAlgorithmV2 {
// Configuration
@Override
public Version version() {
return MPAlgorithm.Version.V3;
}
}

View File

@@ -0,0 +1,84 @@
//==============================================================================
// 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.Joiner;
import com.google.common.io.ByteStreams;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.io.*;
import java.util.Locale;
import javax.annotation.Nonnull;
/**
* @author lhunath, 2018-05-22
*/
public final class Native {
private static final Logger logger = Logger.get( Native.class );
@SuppressWarnings("HardcodedFileSeparator")
private static final char RESOURCE_SEPARATOR = '/';
private static final char EXTENSION_SEPARATOR = '.';
private static final String NATIVES_PATH = "lib";
@SuppressWarnings({ "HardcodedFileSeparator", "LoadLibraryWithNonConstantString" })
public static void load(final Class<?> context, final String name) {
try {
// Find and open a stream to the packaged library resource.
String library = System.mapLibraryName( name );
int libraryDot = library.lastIndexOf( EXTENSION_SEPARATOR );
String libraryName = (libraryDot > 0)? library.substring( 0, libraryDot ): library;
String libraryExtension = (libraryDot > 0)? library.substring( libraryDot ): ".lib";
String libraryResource = getLibraryResource( library );
InputStream libraryStream = context.getResourceAsStream( libraryResource );
if (libraryStream == null)
throw new IllegalStateException(
"Library: " + name + " (" + libraryResource + "), not found in class loader for: " + context );
// Write the library resource to a temporary file.
File libraryFile = File.createTempFile( libraryName, libraryExtension );
FileOutputStream libraryFileStream = new FileOutputStream( libraryFile );
try {
libraryFile.deleteOnExit();
ByteStreams.copy( libraryStream, libraryFileStream );
}
finally {
libraryFileStream.close();
libraryStream.close();
}
// Load the library from the temporary file.
System.load( libraryFile.getAbsolutePath() );
}
catch (final IOException e) {
throw new IllegalStateException( "Couldn't extract library: " + name, e );
}
}
@Nonnull
private static String getLibraryResource(final String library) {
String system = System.getProperty( "os.name" ).toLowerCase( Locale.ROOT );
String architecture = System.getProperty( "os.arch" ).toLowerCase( Locale.ROOT );
if ("Mac OS X".equalsIgnoreCase( system ))
system = "macos";
return Joiner.on( RESOURCE_SEPARATOR ).join( "", NATIVES_PATH, system, architecture, library );
}
}

View File

@@ -0,0 +1,25 @@
//==============================================================================
// 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/>.
//==============================================================================
/**
* @author lhunath, 2018-05-15
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword.impl;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@@ -0,0 +1,26 @@
//==============================================================================
// 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/>.
//==============================================================================
/**
* @author lhunath, 15-02-04
*/
@ParametersAreNonnullByDefault
package com.lyndir.masterpassword;
import javax.annotation.ParametersAreNonnullByDefault;