Marshal refactoring to prepare for new format.
This commit is contained in:
@@ -18,6 +18,9 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2016-10-29
|
||||
@@ -38,4 +41,6 @@ public final class MPConstant {
|
||||
/* Algorithm */
|
||||
|
||||
public static final int MS_PER_S = 1000;
|
||||
|
||||
public static final DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//==============================================================================
|
||||
// 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.primitives.UnsignedInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2017-09-20
|
||||
*/
|
||||
public final class MPUtils {
|
||||
|
||||
public static byte[] bytesForInt(final int number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MasterKeyV0.mpw_byteOrder ).putInt( number ).array();
|
||||
}
|
||||
|
||||
public static byte[] bytesForInt(final UnsignedInteger number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MasterKeyV0.mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||
}
|
||||
|
||||
public static byte[] idForBytes(final byte[] bytes) {
|
||||
return MasterKeyV0.mpw_hash.of( bytes );
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,11 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.strf;
|
||||
import static com.lyndir.masterpassword.MPUtils.idForBytes;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -32,86 +30,25 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public abstract class MasterKey {
|
||||
public class MasterKey {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKey.class );
|
||||
private static boolean allowNativeByDefault = true;
|
||||
private static final Logger logger = Logger.get( MasterKey.class );
|
||||
|
||||
@Nonnull
|
||||
private final String fullName;
|
||||
private boolean allowNative = allowNativeByDefault;
|
||||
private final char[] masterPassword;
|
||||
|
||||
@Nullable
|
||||
private byte[] masterKey;
|
||||
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
public static MasterKey create(final String fullName, final char[] masterPassword) {
|
||||
|
||||
return create( Version.CURRENT, fullName, masterPassword );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
public static MasterKey create(final Version version, final String fullName, final char[] masterPassword) {
|
||||
|
||||
switch (version) {
|
||||
case V0:
|
||||
return new MasterKeyV0( fullName ).revalidate( masterPassword );
|
||||
case V1:
|
||||
return new MasterKeyV1( fullName ).revalidate( masterPassword );
|
||||
case V2:
|
||||
return new MasterKeyV2( fullName ).revalidate( masterPassword );
|
||||
case V3:
|
||||
return new MasterKeyV3( fullName ).revalidate( masterPassword );
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException( strf( "Unsupported version: %s", version ) );
|
||||
}
|
||||
|
||||
public static boolean isAllowNativeByDefault() {
|
||||
return allowNativeByDefault;
|
||||
}
|
||||
|
||||
/**
|
||||
* Native libraries are useful for speeding up the performance of cryptographical functions.
|
||||
* Sometimes, however, we may prefer to use Java-only code.
|
||||
* For instance, for auditability / trust or because the native code doesn't work on our CPU/platform.
|
||||
* <p/>
|
||||
* This setter affects the default setting for any newly created {@link MasterKey}s.
|
||||
*
|
||||
* @param allowNative false to disallow the use of native libraries.
|
||||
*/
|
||||
public static void setAllowNativeByDefault(final boolean allowNative) {
|
||||
allowNativeByDefault = allowNative;
|
||||
}
|
||||
|
||||
protected MasterKey(final String fullName) {
|
||||
Preconditions.checkArgument( !fullName.isEmpty() );
|
||||
@SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
|
||||
public MasterKey(final String fullName, final char[] masterPassword) {
|
||||
|
||||
this.fullName = fullName;
|
||||
logger.trc( "fullName: %s", fullName );
|
||||
this.masterPassword = masterPassword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the master key for a user based on their name and master password.
|
||||
*
|
||||
* @param masterPassword The user's master password.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
protected abstract byte[] deriveKey(char[] masterPassword);
|
||||
|
||||
/**
|
||||
* Derive the site key for a user's site from the given master key and site parameters.
|
||||
*
|
||||
* @param siteName A site identifier.
|
||||
* @param siteCounter The result identifier.
|
||||
* @param keyPurpose The intended purpose for this site key.
|
||||
* @param keyContext A site-scoped key modifier.
|
||||
*/
|
||||
protected abstract byte[] siteKey(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext);
|
||||
private byte[] getKey(final Version algorithmVersion) {
|
||||
// TODO: Cache keys.
|
||||
return algorithmVersion.getAlgorithm().deriveKey( fullName, masterPassword );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a site result token.
|
||||
@@ -122,16 +59,14 @@ public abstract class MasterKey {
|
||||
* @param keyContext A site-scoped result modifier.
|
||||
* @param resultType The type of result to generate.
|
||||
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
||||
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
|
||||
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||
*/
|
||||
public abstract String siteResult(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
protected abstract String sitePasswordFromTemplate(byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
protected abstract String sitePasswordFromCrypt(byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
protected abstract String sitePasswordFromDerive(byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||
final Version algorithmVersion) {
|
||||
return algorithmVersion.getAlgorithm().siteResult(
|
||||
getKey( algorithmVersion ), siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt a stateful site token for persistence.
|
||||
@@ -142,12 +77,14 @@ public abstract class MasterKey {
|
||||
* @param keyContext A site-scoped key modifier.
|
||||
* @param resultType The type of result token to encrypt.
|
||||
* @param resultParam The result token desired from
|
||||
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String)}.
|
||||
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
||||
*/
|
||||
public abstract String siteState(String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
public abstract Version getAlgorithmVersion();
|
||||
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||
final Version algorithmVersion) {
|
||||
return algorithmVersion.getAlgorithm().siteState(
|
||||
getKey( algorithmVersion ), siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getFullName() {
|
||||
@@ -155,63 +92,11 @@ public abstract class MasterKey {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public boolean isAllowNative() {
|
||||
return allowNative;
|
||||
public byte[] getKeyID(final Version algorithmVersion) {
|
||||
|
||||
return idForBytes( getKey( algorithmVersion ) );
|
||||
}
|
||||
|
||||
public MasterKey setAllowNative(final boolean allowNative) {
|
||||
this.allowNative = allowNative;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected byte[] getKey() {
|
||||
|
||||
Preconditions.checkState( isValid() );
|
||||
return Preconditions.checkNotNull( masterKey );
|
||||
}
|
||||
|
||||
public byte[] getKeyID() {
|
||||
|
||||
return idForBytes( getKey() );
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return masterKey != null;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
|
||||
if (masterKey != null) {
|
||||
Arrays.fill( masterKey, (byte) 0 );
|
||||
masterKey = null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodCanBeVariableArityMethod")
|
||||
public MasterKey revalidate(final char[] masterPassword) {
|
||||
invalidate();
|
||||
|
||||
logger.trc( "masterPassword: %s", new String( masterPassword ) );
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
masterKey = deriveKey( masterPassword );
|
||||
|
||||
if (masterKey == null)
|
||||
logger.dbg( "masterKey calculation failed after %.2fs.", (double) (System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
|
||||
else
|
||||
logger.trc( "masterKey ID: %s (derived in %.2fs)", CodeUtils.encodeHex( idForBytes( masterKey ) ),
|
||||
(double) (System.currentTimeMillis() - start) / MPConstant.MS_PER_S );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected abstract byte[] bytesForInt(int number);
|
||||
|
||||
protected abstract byte[] bytesForInt(UnsignedInteger number);
|
||||
|
||||
protected abstract byte[] idForBytes(byte[] bytes);
|
||||
|
||||
public enum Version {
|
||||
/**
|
||||
* bugs:
|
||||
@@ -219,26 +104,36 @@ public abstract class MasterKey {
|
||||
* - miscounted the byte-length for multi-byte site names.
|
||||
* - miscounted the byte-length for multi-byte full names.
|
||||
*/
|
||||
V0,
|
||||
V0( new MasterKeyV0() ),
|
||||
/**
|
||||
* bugs:
|
||||
* - miscounted the byte-length for multi-byte site names.
|
||||
* - miscounted the byte-length for multi-byte full names.
|
||||
*/
|
||||
V1,
|
||||
V1( new MasterKeyV1() ),
|
||||
/**
|
||||
* bugs:
|
||||
* - miscounted the byte-length for multi-byte full names.
|
||||
*/
|
||||
V2,
|
||||
V2( new MasterKeyV2() ),
|
||||
/**
|
||||
* bugs:
|
||||
* - no known issues.
|
||||
*/
|
||||
V3;
|
||||
V3( new MasterKeyV3() );
|
||||
|
||||
public static final Version CURRENT = V3;
|
||||
|
||||
private final MasterKeyAlgorithm algorithm;
|
||||
|
||||
Version(final MasterKeyAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public MasterKeyAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
public static Version fromInt(final int algorithmVersion) {
|
||||
|
||||
return values()[algorithmVersion];
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//==============================================================================
|
||||
// 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.primitives.UnsignedInteger;
|
||||
import java.io.Serializable;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @see MasterKey.Version
|
||||
*/
|
||||
public interface MasterKeyAlgorithm extends Serializable {
|
||||
|
||||
MasterKey.Version getAlgorithmVersion();
|
||||
|
||||
byte[] deriveKey(String fullName, char[] masterPassword);
|
||||
|
||||
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext);
|
||||
|
||||
String siteResult(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||
|
||||
String siteState(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||
}
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.base.*;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
@@ -36,14 +38,11 @@ import javax.crypto.IllegalBlockSizeException;
|
||||
|
||||
|
||||
/**
|
||||
* bugs:
|
||||
* - V2: miscounted the byte-length for multi-byte full names.
|
||||
* - V1: miscounted the byte-length for multi-byte site names.
|
||||
* - V0: does math with chars whose signedness was platform-dependent.
|
||||
* @see MasterKey.Version#V0
|
||||
*
|
||||
* @author lhunath, 2014-08-30
|
||||
*/
|
||||
public class MasterKeyV0 extends MasterKey {
|
||||
public class MasterKeyV0 implements MasterKeyAlgorithm {
|
||||
|
||||
/**
|
||||
* mpw: validity for the time-based rolling counter.
|
||||
@@ -82,25 +81,18 @@ public class MasterKeyV0 extends MasterKey {
|
||||
*/
|
||||
protected static final int scrypt_N = 32768;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKeyV0.class );
|
||||
protected final Logger logger = Logger.get( getClass() );
|
||||
|
||||
public MasterKeyV0(final String fullName) {
|
||||
super( fullName );
|
||||
@Override
|
||||
public MasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
return MasterKey.Version.V0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getAlgorithmVersion() {
|
||||
|
||||
return Version.V0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected byte[] deriveKey(final char[] masterPassword) {
|
||||
public byte[] deriveKey(final String fullName, final char[] masterPassword) {
|
||||
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||
|
||||
String fullName = getFullName();
|
||||
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
||||
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
||||
ByteBuffer mpBytesBuf = mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
|
||||
@@ -127,28 +119,26 @@ public class MasterKeyV0 extends MasterKey {
|
||||
byte[] masterKey = scrypt( masterKeySalt, mpBytes ); // TODO: Why not mpBytesBuf.array()?
|
||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||
Arrays.fill( mpBytes, (byte) 0 );
|
||||
logger.trc( " => masterKey.id: %s", (masterKey == null)? null: (Object) idForBytes( masterKey ) );
|
||||
logger.trc( " => masterKey.id: %s", (Object) idForBytes( masterKey ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||
try {
|
||||
if (isAllowNative())
|
||||
// if (isAllowNative())
|
||||
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||
else
|
||||
return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||
// else
|
||||
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
||||
}
|
||||
catch (final GeneralSecurityException e) {
|
||||
logger.bug( e );
|
||||
return null;
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] siteKey(final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext) {
|
||||
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext) {
|
||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||
|
||||
logger.trc( "-- mpw_siteKey (algorithm: %u)", getAlgorithmVersion().toInt() );
|
||||
@@ -179,7 +169,6 @@ public class MasterKeyV0 extends MasterKey {
|
||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||
|
||||
byte[] masterKey = getKey();
|
||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", (Object) idForBytes( masterKey ) );
|
||||
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
||||
logger.trc( " => siteKey.id: %s", (Object) idForBytes( sitePasswordSeedBytes ) );
|
||||
@@ -188,10 +177,10 @@ public class MasterKeyV0 extends MasterKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
public String siteResult(final byte[] masterKey, final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext );
|
||||
byte[] siteKey = siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||
|
||||
logger.trc( "-- mpw_siteResult (algorithm: %u)", getAlgorithmVersion().toInt() );
|
||||
logger.trc( "resultType: %d (%s)", resultType.toInt(), resultType.getShortName() );
|
||||
@@ -199,18 +188,18 @@ public class MasterKeyV0 extends MasterKey {
|
||||
|
||||
switch (resultType.getTypeClass()) {
|
||||
case Template:
|
||||
return sitePasswordFromTemplate( siteKey, resultType, resultParam );
|
||||
return sitePasswordFromTemplate( masterKey, siteKey, resultType, resultParam );
|
||||
case Stateful:
|
||||
return sitePasswordFromCrypt( siteKey, resultType, resultParam );
|
||||
return sitePasswordFromCrypt( masterKey, siteKey, resultType, resultParam );
|
||||
case Derive:
|
||||
return sitePasswordFromDerive( siteKey, resultType, resultParam );
|
||||
return sitePasswordFromDerive( masterKey, siteKey, resultType, resultParam );
|
||||
}
|
||||
|
||||
throw logger.bug( "Unsupported result type class: %s", resultType.getTypeClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sitePasswordFromTemplate(final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
int[] _siteKey = new int[siteKey.length];
|
||||
for (int i = 0; i < siteKey.length; ++i) {
|
||||
@@ -244,7 +233,7 @@ public class MasterKeyV0 extends MasterKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sitePasswordFromCrypt(final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
Preconditions.checkNotNull( resultParam );
|
||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||
@@ -255,7 +244,7 @@ public class MasterKeyV0 extends MasterKey {
|
||||
logger.trc( "b64 decoded: %zu bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||
|
||||
// Decrypt
|
||||
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, getKey(), true );
|
||||
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
||||
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
||||
logger.trc( "decrypted -> plainText: %s", plainText );
|
||||
|
||||
@@ -267,7 +256,7 @@ public class MasterKeyV0 extends MasterKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sitePasswordFromDerive(final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
if (resultType == MPResultType.DeriveKey) {
|
||||
Preconditions.checkNotNull( resultParam );
|
||||
@@ -296,7 +285,7 @@ public class MasterKeyV0 extends MasterKey {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
public String siteState(final byte[] masterKey, final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
Preconditions.checkNotNull( resultParam );
|
||||
@@ -305,7 +294,7 @@ public class MasterKeyV0 extends MasterKey {
|
||||
try {
|
||||
// Encrypt
|
||||
ByteBuffer plainText = mpw_charset.encode( CharBuffer.wrap( resultParam ) );
|
||||
byte[] cipherBuf = CryptUtils.encrypt( plainText.array(), getKey(), true );
|
||||
byte[] cipherBuf = CryptUtils.encrypt( plainText.array(), masterKey, true );
|
||||
logger.trc( "cipherBuf: %zu bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||
|
||||
// Base64-encode
|
||||
@@ -318,19 +307,4 @@ public class MasterKeyV0 extends MasterKey {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] bytesForInt(final int number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number ).array();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] bytesForInt(final UnsignedInteger number) {
|
||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] idForBytes(final byte[] bytes) {
|
||||
return mpw_hash.of( bytes );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@@ -33,21 +31,14 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class MasterKeyV1 extends MasterKeyV0 {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKeyV1.class );
|
||||
@Override
|
||||
public MasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
public MasterKeyV1(final String fullName) {
|
||||
super( fullName );
|
||||
return MasterKey.Version.V1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getAlgorithmVersion() {
|
||||
|
||||
return Version.V1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String sitePasswordFromTemplate(final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
||||
|
||||
logger.trc( "-- mpw_siteResult (algorithm: %u)", getAlgorithmVersion().toInt() );
|
||||
logger.trc( "resultType: %d (%s)", resultType.toInt(), resultType.getShortName() );
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.*;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@@ -34,21 +35,14 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class MasterKeyV2 extends MasterKeyV1 {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKeyV2.class );
|
||||
@Override
|
||||
public MasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
public MasterKeyV2(final String fullName) {
|
||||
super( fullName );
|
||||
return MasterKey.Version.V2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getAlgorithmVersion() {
|
||||
|
||||
return Version.V2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] siteKey(final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||
@Nullable final String keyContext) {
|
||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||
|
||||
@@ -80,7 +74,6 @@ public class MasterKeyV2 extends MasterKeyV1 {
|
||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
|
||||
|
||||
byte[] masterKey = getKey();
|
||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", (Object) idForBytes( masterKey ) );
|
||||
byte[] sitePasswordSeedBytes = MasterKeyV0.mpw_digest.of( masterKey, sitePasswordInfo );
|
||||
logger.trc( " => siteKey.id: %s", (Object) idForBytes( sitePasswordSeedBytes ) );
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
package com.lyndir.masterpassword;
|
||||
|
||||
import static com.lyndir.masterpassword.MPUtils.idForBytes;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.Arrays;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,27 +36,18 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class MasterKeyV3 extends MasterKeyV2 {
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
private static final Logger logger = Logger.get( MasterKeyV3.class );
|
||||
@Override
|
||||
public MasterKey.Version getAlgorithmVersion() {
|
||||
|
||||
public MasterKeyV3(final String fullName) {
|
||||
super( fullName );
|
||||
return MasterKey.Version.V3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version getAlgorithmVersion() {
|
||||
|
||||
return Version.V3;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected byte[] deriveKey(final char[] masterPassword) {
|
||||
public byte[] deriveKey(final String fullName, final char[] masterPassword) {
|
||||
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||
|
||||
String fullName = getFullName();
|
||||
byte[] fullNameBytes = fullName.getBytes( MasterKeyV0.mpw_charset );
|
||||
byte[] fullNameLengthBytes = bytesForInt( fullNameBytes.length );
|
||||
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
||||
ByteBuffer mpBytesBuf = MasterKeyV0.mpw_charset.encode( CharBuffer.wrap( masterPassword ) );
|
||||
|
||||
logger.trc( "-- mpw_masterKey (algorithm: %u)", getAlgorithmVersion().toInt() );
|
||||
@@ -81,7 +72,7 @@ public class MasterKeyV3 extends MasterKeyV2 {
|
||||
byte[] masterKey = scrypt( masterKeySalt, mpBytes ); // TODO: Why not mpBytesBuf.array()?
|
||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||
Arrays.fill( mpBytes, (byte) 0 );
|
||||
logger.trc( " => masterKey.id: %s", (masterKey == null)? null: (Object) idForBytes( masterKey ) );
|
||||
logger.trc( " => masterKey.id: %s", (Object) idForBytes( masterKey ) );
|
||||
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user