Replace Version API with MPAlgorithm, make configuration instance-specific.
This commit is contained in:
parent
33f2e0edda
commit
82e2d0b5ac
@ -30,89 +30,102 @@ import javax.annotation.Nullable;
|
|||||||
/**
|
/**
|
||||||
* @see MPMasterKey.Version
|
* @see MPMasterKey.Version
|
||||||
*/
|
*/
|
||||||
public interface MPAlgorithm {
|
@SuppressWarnings({ "FieldMayBeStatic", "NewMethodNamingConvention" })
|
||||||
|
public abstract class MPAlgorithm {
|
||||||
|
|
||||||
|
public abstract byte[] masterKey(String fullName, char[] masterPassword);
|
||||||
|
|
||||||
|
public abstract byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext);
|
||||||
|
|
||||||
|
public abstract String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
public abstract String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
public abstract String sitePasswordFromCrypt(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
public abstract String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
|
public abstract String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
|
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
|
||||||
|
public abstract MPMasterKey.Version version();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: defaults: password result type.
|
* mpw: defaults: password result type.
|
||||||
*/
|
*/
|
||||||
MPResultType mpw_default_type = MPResultType.GeneratedLong;
|
public abstract MPResultType mpw_default_type();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: defaults: initial counter value.
|
* mpw: defaults: initial counter value.
|
||||||
*/
|
*/
|
||||||
UnsignedInteger mpw_default_counter = UnsignedInteger.ONE;
|
public abstract UnsignedInteger mpw_default_counter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: validity for the time-based rolling counter.
|
* mpw: validity for the time-based rolling counter (s).
|
||||||
*/
|
*/
|
||||||
int mpw_otp_window = 5 * 60 /* s */;
|
public abstract long mpw_otp_window();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: Key ID hash.
|
* mpw: Key ID hash.
|
||||||
*/
|
*/
|
||||||
MessageDigests mpw_hash = MessageDigests.SHA256;
|
public abstract MessageDigests mpw_hash();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: Site digest.
|
* mpw: Site digest.
|
||||||
*/
|
*/
|
||||||
MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
public abstract MessageAuthenticationDigests mpw_digest();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: Platform-agnostic byte order.
|
* mpw: Platform-agnostic byte order.
|
||||||
*/
|
*/
|
||||||
ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
public abstract ByteOrder mpw_byteOrder();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: Input character encoding.
|
* mpw: Input character encoding.
|
||||||
*/
|
*/
|
||||||
Charset mpw_charset = Charsets.UTF_8;
|
public abstract Charset mpw_charset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: Master key size (byte).
|
* mpw: Master key size (byte).
|
||||||
*/
|
*/
|
||||||
int mpw_dkLen = 64;
|
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();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scrypt: Parallelization parameter.
|
* scrypt: Parallelization parameter.
|
||||||
*/
|
*/
|
||||||
int scrypt_p = 2;
|
public abstract int scrypt_p();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scrypt: Memory cost parameter.
|
* scrypt: Memory cost parameter.
|
||||||
*/
|
*/
|
||||||
int scrypt_r = 8;
|
public abstract int scrypt_r();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scrypt: CPU cost parameter.
|
* scrypt: CPU cost parameter.
|
||||||
*/
|
*/
|
||||||
int scrypt_N = 32768;
|
public abstract int scrypt_N();
|
||||||
|
|
||||||
MPMasterKey.Version getAlgorithmVersion();
|
|
||||||
|
|
||||||
byte[] masterKey(String fullName, char[] masterPassword);
|
|
||||||
|
|
||||||
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
|
||||||
@Nullable String keyContext);
|
|
||||||
|
|
||||||
String siteResult(byte[] masterKey, byte[] siteKey, 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, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
|
||||||
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
|
|
||||||
byte[] toBytes(int number);
|
abstract byte[] toBytes(int number);
|
||||||
|
|
||||||
byte[] toBytes(UnsignedInteger number);
|
abstract byte[] toBytes(UnsignedInteger number);
|
||||||
|
|
||||||
byte[] toBytes(char[] characters);
|
abstract byte[] toBytes(char[] characters);
|
||||||
|
|
||||||
byte[] toID(byte[] bytes);
|
abstract byte[] toID(byte[] bytes);
|
||||||
}
|
}
|
||||||
|
@ -18,17 +18,16 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.*;
|
||||||
import com.google.common.base.Throwables;
|
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lambdaworks.crypto.SCrypt;
|
import com.lambdaworks.crypto.SCrypt;
|
||||||
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.*;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.*;
|
||||||
import java.nio.CharBuffer;
|
import java.nio.charset.Charset;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -40,20 +39,17 @@ import javax.crypto.IllegalBlockSizeException;
|
|||||||
* @author lhunath, 2014-08-30
|
* @author lhunath, 2014-08-30
|
||||||
* @see MPMasterKey.Version#V0
|
* @see MPMasterKey.Version#V0
|
||||||
*/
|
*/
|
||||||
public class MPAlgorithmV0 implements MPAlgorithm {
|
@SuppressWarnings("NewMethodNamingConvention")
|
||||||
|
public class MPAlgorithmV0 extends MPAlgorithm {
|
||||||
|
|
||||||
|
public final MPMasterKey.Version version = MPMasterKey.Version.V0;
|
||||||
|
|
||||||
protected final Logger logger = Logger.get( getClass() );
|
protected final Logger logger = Logger.get( getClass() );
|
||||||
|
|
||||||
@Override
|
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return MPMasterKey.Version.V0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
byte[] fullNameBytes = fullName.getBytes( mpw_charset() );
|
||||||
byte[] fullNameLengthBytes = toBytes( fullName.length() );
|
byte[] fullNameLengthBytes = toBytes( fullName.length() );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
@ -62,12 +58,12 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset() ), fullNameLengthBytes, fullNameBytes );
|
||||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( toID( masterKeySalt ) ) );
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( toID( masterKeySalt ) ) );
|
||||||
|
|
||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||||
scrypt_N, scrypt_r, scrypt_p );
|
scrypt_N(), scrypt_r(), scrypt_p() );
|
||||||
byte[] masterPasswordBytes = toBytes( masterPassword );
|
byte[] masterPasswordBytes = toBytes( masterPassword );
|
||||||
byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
|
byte[] masterKey = scrypt( masterKeySalt, masterPasswordBytes );
|
||||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||||
@ -79,7 +75,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||||
try {
|
try {
|
||||||
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N(), scrypt_r(), scrypt_p(), mpw_dkLen() );
|
||||||
}
|
}
|
||||||
catch (final GeneralSecurityException e) {
|
catch (final GeneralSecurityException e) {
|
||||||
throw logger.bug( e );
|
throw logger.bug( e );
|
||||||
@ -95,25 +91,25 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter.longValue() == 0)
|
if (siteCounter.longValue() == 0)
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window() * 1000)) * mpw_otp_window() );
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset() );
|
||||||
byte[] siteNameLengthBytes = toBytes( siteName.length() );
|
byte[] siteNameLengthBytes = toBytes( siteName.length() );
|
||||||
byte[] siteCounterBytes = toBytes( siteCounter );
|
byte[] siteCounterBytes = toBytes( siteCounter );
|
||||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset() );
|
||||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: toBytes( keyContextBytes.length );
|
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: toBytes( keyContextBytes.length );
|
||||||
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||||
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||||
|
|
||||||
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset() ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||||
if (keyContextBytes != null)
|
if (keyContextBytes != null)
|
||||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( toID( masterKey ) ) );
|
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( toID( masterKey ) ) );
|
||||||
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
byte[] sitePasswordSeedBytes = mpw_digest().of( masterKey, sitePasswordInfo );
|
||||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
return sitePasswordSeedBytes;
|
return sitePasswordSeedBytes;
|
||||||
@ -142,7 +138,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
int[] _siteKey = new int[siteKey.length];
|
int[] _siteKey = new int[siteKey.length];
|
||||||
for (int i = 0; i < siteKey.length; ++i) {
|
for (int i = 0; i < siteKey.length; ++i) {
|
||||||
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder );
|
ByteBuffer buf = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() );
|
||||||
Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
|
Arrays.fill( buf.array(), (byte) ((siteKey[i] > 0)? 0x00: 0xFF) );
|
||||||
buf.position( 2 );
|
buf.position( 2 );
|
||||||
buf.put( siteKey[i] ).rewind();
|
buf.put( siteKey[i] ).rewind();
|
||||||
@ -185,7 +181,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
// Decrypt
|
// Decrypt
|
||||||
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
||||||
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
String plainText = mpw_charset().decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
||||||
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
|
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
|
||||||
|
|
||||||
return plainText;
|
return plainText;
|
||||||
@ -202,14 +198,14 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
if (resultType == MPResultType.DeriveKey) {
|
if (resultType == MPResultType.DeriveKey) {
|
||||||
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
||||||
if (resultParamInt == 0)
|
if (resultParamInt == 0)
|
||||||
resultParamInt = 512;
|
resultParamInt = mpw_keySize_max();
|
||||||
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
|
if ((resultParamInt < mpw_keySize_min()) || (resultParamInt > mpw_keySize_max()) || ((resultParamInt % 8) != 0))
|
||||||
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
||||||
int keySize = resultParamInt / 8;
|
int keySize = resultParamInt / 8;
|
||||||
logger.trc( "keySize: %d", keySize );
|
logger.trc( "keySize: %d", keySize );
|
||||||
|
|
||||||
// Derive key
|
// Derive key
|
||||||
byte[] resultKey = null; // TODO: mpw_kdf_blake2b( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
byte[] resultKey = null; // TODO: mpw_kdf_blake2b()( keySize, siteKey, MPSiteKeySize, NULL, 0, 0, NULL );
|
||||||
if (resultKey == null)
|
if (resultKey == null)
|
||||||
throw logger.bug( "Could not derive result key." );
|
throw logger.bug( "Could not derive result key." );
|
||||||
|
|
||||||
@ -229,7 +225,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Encrypt
|
// Encrypt
|
||||||
byte[] cipherBuf = CryptUtils.encrypt( resultParam.getBytes( mpw_charset ), masterKey, true );
|
byte[] cipherBuf = CryptUtils.encrypt( resultParam.getBytes( mpw_charset() ), masterKey, true );
|
||||||
logger.trc( "cipherBuf: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
logger.trc( "cipherBuf: %d bytes = %s", cipherBuf.length, CodeUtils.encodeHex( cipherBuf ) );
|
||||||
|
|
||||||
// Base64-encode
|
// Base64-encode
|
||||||
@ -243,21 +239,139 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version version() {
|
||||||
|
return MPMasterKey.Version.V0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: defaults: password result type.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MPResultType mpw_default_type() {
|
||||||
|
return MPResultType.GeneratedLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: defaults: initial counter value.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public UnsignedInteger mpw_default_counter() {
|
||||||
|
return UnsignedInteger.ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: validity for the time-based rolling counter.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public long mpw_otp_window() {
|
||||||
|
return 5 * 60 /* s */;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Key ID hash.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MessageDigests mpw_hash() {
|
||||||
|
return MessageDigests.SHA256;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Site digest.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MessageAuthenticationDigests mpw_digest() {
|
||||||
|
return MessageAuthenticationDigests.HmacSHA256;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Platform-agnostic byte order.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ByteOrder mpw_byteOrder() {
|
||||||
|
return ByteOrder.BIG_ENDIAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Input character encoding.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Charset mpw_charset() {
|
||||||
|
return Charsets.UTF_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Master key size (byte).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int mpw_dkLen() {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Minimum size for derived keys (bit).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int mpw_keySize_min() {
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Maximum size for derived keys (bit).
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int mpw_keySize_max() {
|
||||||
|
return 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Parallelization parameter.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int scrypt_p() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Memory cost parameter.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int scrypt_r() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: CPU cost parameter.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
|
public int scrypt_N() {
|
||||||
|
return 32768;
|
||||||
|
}
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] toBytes(final int number) {
|
public byte[] toBytes(final int number) {
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number ).array();
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number ).array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] toBytes(final UnsignedInteger number) {
|
public byte[] toBytes(final UnsignedInteger number) {
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number.intValue() ).array();
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder() ).putInt( number.intValue() ).array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] toBytes(final char[] characters) {
|
public byte[] toBytes(final char[] characters) {
|
||||||
ByteBuffer byteBuffer = mpw_charset.encode( CharBuffer.wrap( characters ) );
|
ByteBuffer byteBuffer = mpw_charset().encode( CharBuffer.wrap( characters ) );
|
||||||
|
|
||||||
byte[] bytes = new byte[byteBuffer.remaining()];
|
byte[] bytes = new byte[byteBuffer.remaining()];
|
||||||
byteBuffer.get( bytes );
|
byteBuffer.get( bytes );
|
||||||
@ -268,6 +382,6 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] toID(final byte[] bytes) {
|
public byte[] toID(final byte[] bytes) {
|
||||||
return mpw_hash.of( bytes );
|
return mpw_hash().of( bytes );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,6 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
||||||
|
|
||||||
@Override
|
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return MPMasterKey.Version.V1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
@Nullable final String resultParam) {
|
@Nullable final String resultParam) {
|
||||||
@ -60,4 +54,11 @@ public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
|||||||
|
|
||||||
return password.toString();
|
return password.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version version() {
|
||||||
|
return MPMasterKey.Version.V1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,6 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
||||||
|
|
||||||
@Override
|
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return MPMasterKey.Version.V2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] siteKey(final byte[] masterKey, 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) {
|
@Nullable final String keyContext) {
|
||||||
@ -45,27 +39,34 @@ public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
|||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter.longValue() == 0)
|
if (siteCounter.longValue() == 0)
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window() * 1000)) * mpw_otp_window() );
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset() );
|
||||||
byte[] siteNameLengthBytes = toBytes( siteNameBytes.length );
|
byte[] siteNameLengthBytes = toBytes( siteNameBytes.length );
|
||||||
byte[] siteCounterBytes = toBytes( siteCounter );
|
byte[] siteCounterBytes = toBytes( siteCounter );
|
||||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset() );
|
||||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: toBytes( keyContextBytes.length );
|
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: toBytes( keyContextBytes.length );
|
||||||
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s",
|
||||||
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ),
|
||||||
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
(keyContextLengthBytes == null)? null: CodeUtils.encodeHex( keyContextLengthBytes ), keyContext );
|
||||||
|
|
||||||
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( mpw_charset() ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
||||||
if (keyContextBytes != null)
|
if (keyContextBytes != null)
|
||||||
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
|
||||||
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( toID( masterKey ) ) );
|
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( toID( masterKey ) ) );
|
||||||
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
byte[] sitePasswordSeedBytes = mpw_digest().of( masterKey, sitePasswordInfo );
|
||||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
return sitePasswordSeedBytes;
|
return sitePasswordSeedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version version() {
|
||||||
|
return MPMasterKey.Version.V2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,10 @@ import java.util.Arrays;
|
|||||||
*/
|
*/
|
||||||
public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
||||||
|
|
||||||
@Override
|
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
|
||||||
|
|
||||||
return MPMasterKey.Version.V3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
byte[] fullNameBytes = fullName.getBytes( mpw_charset() );
|
||||||
byte[] fullNameLengthBytes = toBytes( fullNameBytes.length );
|
byte[] fullNameLengthBytes = toBytes( fullNameBytes.length );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
@ -47,12 +41,12 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
|||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset() ), fullNameLengthBytes, fullNameBytes );
|
||||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( toID( masterKeySalt ) ) );
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( toID( masterKeySalt ) ) );
|
||||||
|
|
||||||
// Calculate the master key.
|
// Calculate the master key.
|
||||||
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
logger.trc( "masterKey: scrypt( masterPassword, masterKeySalt, N=%d, r=%d, p=%d )",
|
||||||
scrypt_N, scrypt_r, scrypt_p );
|
scrypt_N(), scrypt_r(), scrypt_p() );
|
||||||
byte[] mpBytes = toBytes( masterPassword );
|
byte[] mpBytes = toBytes( masterPassword );
|
||||||
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
||||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||||
@ -61,4 +55,11 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
|||||||
|
|
||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MPMasterKey.Version version() {
|
||||||
|
return MPMasterKey.Version.V3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ package com.lyndir.masterpassword;
|
|||||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.primitives.UnsignedBytes;
|
||||||
|
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.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
@ -66,7 +68,7 @@ public class MPIdenticon {
|
|||||||
|
|
||||||
IntBuffer identiconSeedBuffer = IntBuffer.allocate( identiconSeedBytes.capacity() );
|
IntBuffer identiconSeedBuffer = IntBuffer.allocate( identiconSeedBytes.capacity() );
|
||||||
while (identiconSeedBytes.hasRemaining())
|
while (identiconSeedBytes.hasRemaining())
|
||||||
identiconSeedBuffer.put( identiconSeedBytes.get() & 0xFF );
|
identiconSeedBuffer.put( UnsignedBytes.toInt( identiconSeedBytes.get() ) );
|
||||||
int[] identiconSeed = identiconSeedBuffer.array();
|
int[] identiconSeed = identiconSeedBuffer.array();
|
||||||
|
|
||||||
color = colors[identiconSeed[4] % colors.length];
|
color = colors[identiconSeed[4] % colors.length];
|
||||||
|
@ -58,21 +58,21 @@ public class MPMasterKey {
|
|||||||
*
|
*
|
||||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
private byte[] masterKey(final Version algorithmVersion)
|
private byte[] masterKey(final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
Preconditions.checkArgument( masterPassword.length > 0 );
|
Preconditions.checkArgument( masterPassword.length > 0 );
|
||||||
|
|
||||||
if (invalidated)
|
if (invalidated)
|
||||||
throw new MPInvalidatedException();
|
throw new MPInvalidatedException();
|
||||||
|
|
||||||
byte[] key = keyByVersion.get( algorithmVersion );
|
byte[] key = keyByVersion.get( algorithm.version() );
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_masterKey (algorithm: %s)", algorithm );
|
||||||
logger.trc( "fullName: %s", fullName );
|
logger.trc( "fullName: %s", fullName );
|
||||||
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex(
|
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex(
|
||||||
algorithmVersion.getAlgorithm().toID( algorithmVersion.getAlgorithm().toBytes( masterPassword ) ) ) );
|
algorithm.toID( algorithm.toBytes( masterPassword ) ) ) );
|
||||||
|
|
||||||
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
|
keyByVersion.put( algorithm.version(), key = algorithm.masterKey( fullName, masterPassword ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
@ -84,19 +84,19 @@ public class MPMasterKey {
|
|||||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
private byte[] siteKey(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final Version algorithmVersion)
|
@Nullable final String keyContext, final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
Preconditions.checkArgument( !siteName.isEmpty() );
|
Preconditions.checkArgument( !siteName.isEmpty() );
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithmVersion );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteKey (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_siteKey (algorithm: %s)", algorithm );
|
||||||
logger.trc( "siteName: %s", siteName );
|
logger.trc( "siteName: %s", siteName );
|
||||||
logger.trc( "siteCounter: %s", siteCounter );
|
logger.trc( "siteCounter: %s", siteCounter );
|
||||||
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
|
logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() );
|
||||||
logger.trc( "keyContext: %s", keyContext );
|
logger.trc( "keyContext: %s", keyContext );
|
||||||
|
|
||||||
return algorithmVersion.getAlgorithm().siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
return algorithm.siteKey( masterKey, siteName, siteCounter, keyPurpose, keyContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,23 +108,23 @@ public class MPMasterKey {
|
|||||||
* @param keyContext A site-scoped result modifier.
|
* @param keyContext A site-scoped result modifier.
|
||||||
* @param resultType The type of result to generate.
|
* @param resultType The type of result to generate.
|
||||||
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
* @param resultParam A parameter for the resultType. For stateful result types, the output of
|
||||||
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
* {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
|
||||||
*
|
*
|
||||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
final Version algorithmVersion)
|
final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithmVersion );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteResult (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_siteResult (algorithm: %s)", algorithm );
|
||||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||||
logger.trc( "resultParam: %s", resultParam );
|
logger.trc( "resultParam: %s", resultParam );
|
||||||
|
|
||||||
return algorithmVersion.getAlgorithm().siteResult(
|
return algorithm.siteResult(
|
||||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,26 +137,26 @@ public class MPMasterKey {
|
|||||||
* @param keyContext A site-scoped key modifier.
|
* @param keyContext A site-scoped key modifier.
|
||||||
* @param resultType The type of result token to encrypt.
|
* @param resultType The type of result token to encrypt.
|
||||||
* @param resultParam The result token desired from
|
* @param resultParam The result token desired from
|
||||||
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}.
|
* {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}.
|
||||||
*
|
*
|
||||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam,
|
||||||
final Version algorithmVersion)
|
final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
Preconditions.checkNotNull( resultParam );
|
Preconditions.checkNotNull( resultParam );
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
|
|
||||||
byte[] masterKey = masterKey( algorithmVersion );
|
byte[] masterKey = masterKey( algorithm );
|
||||||
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion );
|
byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithm );
|
||||||
|
|
||||||
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_siteState (algorithm: %s)", algorithm );
|
||||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||||
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( MPAlgorithm.mpw_charset ).length, resultParam );
|
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( algorithm.mpw_charset() ).length, resultParam );
|
||||||
|
|
||||||
return algorithmVersion.getAlgorithm().siteState(
|
return algorithm.siteState(
|
||||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,10 +171,10 @@ public class MPMasterKey {
|
|||||||
*
|
*
|
||||||
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
* @throws MPInvalidatedException {@link #invalidate()} has been called on this object.
|
||||||
*/
|
*/
|
||||||
public byte[] getKeyID(final Version algorithmVersion)
|
public byte[] getKeyID(final MPAlgorithm algorithm)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
return algorithmVersion.getAlgorithm().toID( masterKey( algorithmVersion ) );
|
return algorithm.toID( masterKey( algorithm ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,6 +31,7 @@ import org.jetbrains.annotations.Contract;
|
|||||||
*
|
*
|
||||||
* @author lhunath
|
* @author lhunath
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("RedundantTypeArguments" /* IDEA-191043 */)
|
||||||
public enum MPResultType {
|
public enum MPResultType {
|
||||||
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
// bit 0-3 | MPResultTypeClass | MPSiteFeature
|
||||||
|
|
||||||
@ -134,7 +135,7 @@ public enum MPResultType {
|
|||||||
private final List<MPTemplate> templates;
|
private final List<MPTemplate> templates;
|
||||||
private final MPResultTypeClass typeClass;
|
private final MPResultTypeClass typeClass;
|
||||||
private final int typeIndex;
|
private final int typeIndex;
|
||||||
private final Set<MPSiteFeature> typeFeatures;
|
private final ImmutableSet<MPSiteFeature> typeFeatures;
|
||||||
|
|
||||||
MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
|
MPResultType(final String shortName, final String description, final List<MPTemplate> templates,
|
||||||
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
|
||||||
@ -166,7 +167,8 @@ public enum MPResultType {
|
|||||||
return typeClass;
|
return typeClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<MPSiteFeature> getTypeFeatures() {
|
@SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */ )
|
||||||
|
public ImmutableSet<MPSiteFeature> getTypeFeatures() {
|
||||||
|
|
||||||
return typeFeatures;
|
return typeFeatures;
|
||||||
}
|
}
|
||||||
@ -232,6 +234,7 @@ public enum MPResultType {
|
|||||||
*
|
*
|
||||||
* @return All types that support the given mask's class & features.
|
* @return All types that support the given mask's class & features.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({ "MagicNumber", "UnnecessaryParentheses" /* IDEA-191040 */ })
|
||||||
public static ImmutableList<MPResultType> forMask(final int mask) {
|
public static ImmutableList<MPResultType> forMask(final int mask) {
|
||||||
|
|
||||||
int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
|
int typeMask = mask & ~0xF; // Ignore resultType bit 0-3
|
||||||
|
@ -35,7 +35,7 @@ public class MPFileSite extends MPSite {
|
|||||||
private String siteContent;
|
private String siteContent;
|
||||||
private UnsignedInteger siteCounter;
|
private UnsignedInteger siteCounter;
|
||||||
private MPResultType resultType;
|
private MPResultType resultType;
|
||||||
private MPMasterKey.Version algorithmVersion;
|
private MPAlgorithm algorithm;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String loginContent;
|
private String loginContent;
|
||||||
@ -49,24 +49,24 @@ public class MPFileSite extends MPSite {
|
|||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName) {
|
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||||
this( user, siteName,
|
this( user, siteName,
|
||||||
user.getAlgorithmVersion().getAlgorithm().mpw_default_counter,
|
user.getAlgorithm().mpw_default_counter(),
|
||||||
user.getAlgorithmVersion().getAlgorithm().mpw_default_type,
|
user.getAlgorithm().mpw_default_type(),
|
||||||
user.getAlgorithmVersion() );
|
user.getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
public MPFileSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
||||||
final MPMasterKey.Version algorithmVersion) {
|
final MPAlgorithm algorithm) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.siteName = siteName;
|
this.siteName = siteName;
|
||||||
this.siteCounter = siteCounter;
|
this.siteCounter = siteCounter;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
this.lastUsed = new Instant();
|
this.lastUsed = new Instant();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent,
|
||||||
final UnsignedInteger siteCounter,
|
final UnsignedInteger siteCounter,
|
||||||
final MPResultType resultType, final MPMasterKey.Version algorithmVersion,
|
final MPResultType resultType, final MPAlgorithm algorithm,
|
||||||
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
@Nullable final String loginContent, @Nullable final MPResultType loginType,
|
||||||
@Nullable final String url, final int uses, final Instant lastUsed) {
|
@Nullable final String url, final int uses, final Instant lastUsed) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
@ -74,7 +74,7 @@ public class MPFileSite extends MPSite {
|
|||||||
this.siteContent = siteContent;
|
this.siteContent = siteContent;
|
||||||
this.siteCounter = siteCounter;
|
this.siteCounter = siteCounter;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
this.loginContent = loginContent;
|
this.loginContent = loginContent;
|
||||||
this.loginType = loginType;
|
this.loginType = loginType;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
@ -129,7 +129,7 @@ public class MPFileSite extends MPSite {
|
|||||||
this.siteContent = null;
|
this.siteContent = null;
|
||||||
else
|
else
|
||||||
this.siteContent = masterKey.siteState(
|
this.siteContent = masterKey.siteState(
|
||||||
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, getAlgorithmVersion() );
|
getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, algorithm );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -153,13 +153,13 @@ public class MPFileSite extends MPSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithmVersion;
|
return algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
public void setAlgorithm(final MPAlgorithm algorithm) {
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -180,8 +180,8 @@ public class MPFileSite extends MPSite {
|
|||||||
this.loginContent = null;
|
this.loginContent = null;
|
||||||
else
|
else
|
||||||
this.loginContent = masterKey.siteState(
|
this.loginContent = masterKey.siteState(
|
||||||
siteName, MPAlgorithm.mpw_default_counter, MPKeyPurpose.Identification, null, this.loginType, result,
|
siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null, this.loginType, result,
|
||||||
algorithmVersion );
|
algorithm );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -22,8 +22,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.masterpassword.*;
|
import com.lyndir.masterpassword.*;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import org.joda.time.Instant;
|
import org.joda.time.Instant;
|
||||||
@ -43,7 +42,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private byte[] keyID;
|
private byte[] keyID;
|
||||||
private MPMasterKey.Version algorithmVersion;
|
private MPAlgorithm algorithm;
|
||||||
private MPMarshalFormat format;
|
private MPMarshalFormat format;
|
||||||
|
|
||||||
private int avatar;
|
private int avatar;
|
||||||
@ -51,18 +50,18 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
private ReadableInstant lastUsed;
|
private ReadableInstant lastUsed;
|
||||||
|
|
||||||
public MPFileUser(final String fullName) {
|
public MPFileUser(final String fullName) {
|
||||||
this( fullName, null, MPMasterKey.Version.CURRENT );
|
this( fullName, null, MPMasterKey.Version.CURRENT.getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm) {
|
||||||
this( fullName, keyID, algorithmVersion, 0, MPAlgorithm.mpw_default_type, new Instant(), MPMarshalFormat.DEFAULT );
|
this( fullName, keyID, algorithm, 0, algorithm.mpw_default_type(), new Instant(), MPMarshalFormat.DEFAULT );
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion, final int avatar,
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPAlgorithm algorithm, final int avatar,
|
||||||
final MPResultType defaultType, final ReadableInstant lastUsed, final MPMarshalFormat format) {
|
final MPResultType defaultType, final ReadableInstant lastUsed, final MPMarshalFormat format) {
|
||||||
this.fullName = fullName;
|
this.fullName = fullName;
|
||||||
this.keyID = (keyID == null)? null: keyID.clone();
|
this.keyID = (keyID == null)? null: keyID.clone();
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
this.defaultType = defaultType;
|
this.defaultType = defaultType;
|
||||||
this.lastUsed = lastUsed;
|
this.lastUsed = lastUsed;
|
||||||
@ -75,12 +74,12 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithmVersion;
|
return algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
public void setAlgorithm(final MPAlgorithm algorithm) {
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MPMarshalFormat getFormat() {
|
public MPMarshalFormat getFormat() {
|
||||||
@ -117,7 +116,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Iterable<MPFileSite> getSites() {
|
public Iterable<MPFileSite> getSites() {
|
||||||
return sites;
|
return Collections.unmodifiableCollection( sites );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -158,8 +157,8 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
try {
|
try {
|
||||||
key = new MPMasterKey( getFullName(), masterPassword );
|
key = new MPMasterKey( getFullName(), masterPassword );
|
||||||
if ((keyID == null) || (keyID.length == 0))
|
if ((keyID == null) || (keyID.length == 0))
|
||||||
keyID = key.getKeyID( algorithmVersion );
|
keyID = key.getKeyID( algorithm );
|
||||||
else if (!Arrays.equals( key.getKeyID( algorithmVersion ), keyID ))
|
else if (!Arrays.equals( key.getKeyID( algorithm ), keyID ))
|
||||||
throw new MPIncorrectMasterPasswordException( this );
|
throw new MPIncorrectMasterPasswordException( this );
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
|
@ -127,7 +127,7 @@ public class MPFileUserManager extends MPUserManager {
|
|||||||
}
|
}
|
||||||
}.write( user.getFormat().marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
|
}.write( user.getFormat().marshaller().marshall( user, masterKey, MPMarshaller.ContentMode.PROTECTED ) );
|
||||||
}
|
}
|
||||||
catch (final IOException e) {
|
catch (final MPMarshalException | IOException e) {
|
||||||
logger.err( e, "Unable to save sites for user: %s", user );
|
logger.err( e, "Unable to save sites for user: %s", user );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ public class MPFlatMarshaller implements MPMarshaller {
|
|||||||
content.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
|
content.append( "# Full Name: " ).append( user.getFullName() ).append( '\n' );
|
||||||
content.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
|
content.append( "# Avatar: " ).append( user.getAvatar() ).append( '\n' );
|
||||||
content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
|
content.append( "# Key ID: " ).append( user.exportKeyID() ).append( '\n' );
|
||||||
content.append( "# Algorithm: " ).append( user.getAlgorithmVersion().toInt() ).append( '\n' );
|
content.append( "# Algorithm: " ).append( user.getAlgorithm().version().toInt() ).append( '\n' );
|
||||||
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
|
content.append( "# Default Type: " ).append( user.getDefaultType().getType() ).append( '\n' );
|
||||||
content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
|
content.append( "# Passwords: " ).append( contentMode.name() ).append( '\n' );
|
||||||
content.append( "##\n" );
|
content.append( "##\n" );
|
||||||
@ -69,7 +69,7 @@ public class MPFlatMarshaller implements MPMarshaller {
|
|||||||
site.getUses(), // uses
|
site.getUses(), // uses
|
||||||
strf( "%d:%d:%d", //
|
strf( "%d:%d:%d", //
|
||||||
site.getResultType().getType(), // type
|
site.getResultType().getType(), // type
|
||||||
site.getAlgorithmVersion().toInt(), // algorithm
|
site.getAlgorithm().version().toInt(), // algorithm
|
||||||
site.getSiteCounter().intValue() ), // counter
|
site.getSiteCounter().intValue() ), // counter
|
||||||
ifNotNullElse( loginName, "" ), // loginName
|
ifNotNullElse( loginName, "" ), // loginName
|
||||||
site.getSiteName(), // siteName
|
site.getSiteName(), // siteName
|
||||||
|
@ -62,7 +62,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
String fullName = null;
|
String fullName = null;
|
||||||
int mpVersion = 0, importFormat = 0, avatar = 0;
|
int mpVersion = 0, importFormat = 0, avatar = 0;
|
||||||
boolean clearContent = false, headerStarted = false;
|
boolean clearContent = false, headerStarted = false;
|
||||||
MPResultType defaultType = MPAlgorithm.mpw_default_type;
|
MPResultType defaultType = null;
|
||||||
|
|
||||||
//noinspection HardcodedLineSeparator
|
//noinspection HardcodedLineSeparator
|
||||||
for (final String line : Splitter.on( CharMatcher.anyOf( "\r\n" ) ).omitEmptyStrings().split( content ))
|
for (final String line : Splitter.on( CharMatcher.anyOf( "\r\n" ) ).omitEmptyStrings().split( content ))
|
||||||
@ -73,8 +73,8 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
headerStarted = true;
|
headerStarted = true;
|
||||||
else
|
else
|
||||||
// Ends the header.
|
// Ends the header.
|
||||||
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ), avatar, defaultType,
|
user = new MPFileUser( fullName, keyID, MPMasterKey.Version.fromInt( mpVersion ).getAlgorithm(),
|
||||||
new DateTime( 0 ), MPMarshalFormat.Flat );
|
avatar, defaultType, new DateTime( 0 ), MPMarshalFormat.Flat );
|
||||||
|
|
||||||
// Comment.
|
// Comment.
|
||||||
else if (line.startsWith( "#" )) {
|
else if (line.startsWith( "#" )) {
|
||||||
@ -114,10 +114,10 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
case 0:
|
case 0:
|
||||||
site = new MPFileSite( user, //
|
site = new MPFileSite( user, //
|
||||||
siteMatcher.group( 5 ), siteMatcher.group( 6 ),
|
siteMatcher.group( 5 ), siteMatcher.group( 6 ),
|
||||||
user.getAlgorithmVersion().getAlgorithm().mpw_default_counter,
|
user.getAlgorithm().mpw_default_counter(),
|
||||||
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
|
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
|
||||||
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
null, null, null, ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
break;
|
break;
|
||||||
@ -128,7 +128,7 @@ public class MPFlatUnmarshaller implements MPUnmarshaller {
|
|||||||
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
|
UnsignedInteger.valueOf( colon.matcher( siteMatcher.group( 5 ) ).replaceAll( "" ) ),
|
||||||
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
MPResultType.forType( ConversionUtils.toIntegerNN( siteMatcher.group( 3 ) ) ),
|
||||||
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
MPMasterKey.Version.fromInt( ConversionUtils.toIntegerNN(
|
||||||
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ),
|
colon.matcher( siteMatcher.group( 4 ) ).replaceAll( "" ) ) ).getAlgorithm(),
|
||||||
siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
|
siteMatcher.group( 6 ), MPResultType.GeneratedName, null,
|
||||||
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
ConversionUtils.toIntegerNN( siteMatcher.group( 2 ) ),
|
||||||
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
MPConstant.dateTimeFormatter.parseDateTime( siteMatcher.group( 1 ) ).toInstant() );
|
||||||
|
@ -43,24 +43,24 @@ public abstract class MPSite {
|
|||||||
|
|
||||||
public abstract void setResultType(MPResultType resultType);
|
public abstract void setResultType(MPResultType resultType);
|
||||||
|
|
||||||
public abstract MPMasterKey.Version getAlgorithmVersion();
|
public abstract MPAlgorithm getAlgorithm();
|
||||||
|
|
||||||
public abstract void setAlgorithmVersion(MPMasterKey.Version algorithmVersion);
|
public abstract void setAlgorithm(MPAlgorithm algorithm);
|
||||||
|
|
||||||
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
public String resultFor(final MPMasterKey masterKey, final MPKeyPurpose keyPurpose, @Nullable final String keyContext,
|
||||||
@Nullable final String siteContent)
|
@Nullable final String siteContent)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
return masterKey.siteResult(
|
return masterKey.siteResult(
|
||||||
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithmVersion() );
|
getSiteName(), getSiteCounter(), keyPurpose, keyContext, getResultType(), siteContent, getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
public String loginFor(final MPMasterKey masterKey, final MPResultType loginType, @Nullable final String loginContent)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
return masterKey.siteResult(
|
return masterKey.siteResult(
|
||||||
getSiteName(), MPAlgorithm.mpw_default_counter, MPKeyPurpose.Identification, null, loginType, loginContent,
|
getSiteName(), getAlgorithm().mpw_default_counter(), MPKeyPurpose.Identification, null, loginType, loginContent,
|
||||||
getAlgorithmVersion() );
|
getAlgorithm() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,8 +22,7 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
|||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
import com.lyndir.masterpassword.MPInvalidatedException;
|
import com.lyndir.masterpassword.*;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -51,10 +50,10 @@ public abstract class MPUser<S extends MPSite> {
|
|||||||
|
|
||||||
public String exportKeyID()
|
public String exportKeyID()
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithmVersion() ) );
|
return CodeUtils.encodeHex( getMasterKey().getKeyID( getAlgorithm() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract MPMasterKey.Version getAlgorithmVersion();
|
public abstract MPAlgorithm getAlgorithm();
|
||||||
|
|
||||||
public int getAvatar() {
|
public int getAvatar() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -171,8 +171,8 @@ public class MPTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPMasterKey.Version getAlgorithm() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) );
|
return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) ).getAlgorithm();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
|
@ -109,14 +109,15 @@ public class MPMasterKeyTest {
|
|||||||
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword );
|
||||||
|
|
||||||
String password = randomString( 8 );
|
String password = randomString( 8 );
|
||||||
|
MPResultType resultType = MPResultType.StoredPersonal;
|
||||||
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
|
for (final MPMasterKey.Version version : MPMasterKey.Version.values()) {
|
||||||
MPResultType resultType = MPResultType.StoredPersonal;
|
MPAlgorithm algorithm = version.getAlgorithm();
|
||||||
|
|
||||||
// Test site state
|
// Test site state
|
||||||
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
String state = masterKey.siteState( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
testCase.getKeyContext(), resultType, password, version );
|
testCase.getKeyContext(), resultType, password, algorithm );
|
||||||
String result = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
String result = masterKey.siteResult( testCase.getSiteName(), testCase.getSiteCounter(), testCase.getKeyPurpose(),
|
||||||
testCase.getKeyContext(), resultType, state, version );
|
testCase.getKeyContext(), resultType, state, algorithm );
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
result,
|
result,
|
||||||
|
@ -303,7 +303,7 @@ public class EmergencyActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version );
|
sitePassword = masterKey.siteResult( siteName, counter, MPKeyPurpose.Authentication, null, type, null, version.getAlgorithm() );
|
||||||
|
|
||||||
runOnUiThread( new Runnable() {
|
runOnUiThread( new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -148,7 +148,7 @@ public final class Preferences {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPResultType getDefaultResultType() {
|
public MPResultType getDefaultResultType() {
|
||||||
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPAlgorithm.mpw_default_type.ordinal() )];
|
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, getDefaultVersion().getAlgorithm().mpw_default_type().ordinal() )];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
||||||
|
@ -38,6 +38,7 @@ import java.util.concurrent.Executors;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("PublicMethodNotExposedInInterface" /* IDEA-191044 */)
|
||||||
public class TestActivity extends Activity implements MPTestSuite.Listener {
|
public class TestActivity extends Activity implements MPTestSuite.Listener {
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
@ -64,6 +65,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener {
|
|||||||
|
|
||||||
private MPTestSuite testSuite;
|
private MPTestSuite testSuite;
|
||||||
private ListenableFuture<Boolean> testFuture;
|
private ListenableFuture<Boolean> testFuture;
|
||||||
|
@Nullable
|
||||||
private Runnable action;
|
private Runnable action;
|
||||||
private ImmutableSet<String> testNames;
|
private ImmutableSet<String> testNames;
|
||||||
|
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
package com.lyndir.masterpassword.gui.model;
|
package com.lyndir.masterpassword.gui.model;
|
||||||
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.*;
|
||||||
import com.lyndir.masterpassword.MPResultType;
|
|
||||||
import com.lyndir.masterpassword.model.MPSite;
|
import com.lyndir.masterpassword.model.MPSite;
|
||||||
|
|
||||||
|
|
||||||
@ -29,17 +28,17 @@ import com.lyndir.masterpassword.model.MPSite;
|
|||||||
*/
|
*/
|
||||||
public class IncognitoSite extends MPSite {
|
public class IncognitoSite extends MPSite {
|
||||||
|
|
||||||
private String siteName;
|
private String siteName;
|
||||||
private UnsignedInteger siteCounter;
|
private UnsignedInteger siteCounter;
|
||||||
private MPResultType resultType;
|
private MPResultType resultType;
|
||||||
private MPMasterKey.Version algorithmVersion;
|
private MPAlgorithm algorithm;
|
||||||
|
|
||||||
public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType,
|
||||||
final MPMasterKey.Version algorithmVersion) {
|
final MPAlgorithm algorithm) {
|
||||||
this.siteName = siteName;
|
this.siteName = siteName;
|
||||||
this.siteCounter = siteCounter;
|
this.siteCounter = siteCounter;
|
||||||
this.resultType = resultType;
|
this.resultType = resultType;
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,13 +62,13 @@ public class IncognitoSite extends MPSite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return algorithmVersion;
|
return algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) {
|
public void setAlgorithm(final MPAlgorithm algorithm) {
|
||||||
this.algorithmVersion = algorithmVersion;
|
this.algorithm = algorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package com.lyndir.masterpassword.gui.model;
|
package com.lyndir.masterpassword.gui.model;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.lyndir.masterpassword.MPAlgorithm;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.MPMasterKey;
|
||||||
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
|
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
|
||||||
import com.lyndir.masterpassword.model.MPUser;
|
import com.lyndir.masterpassword.model.MPUser;
|
||||||
@ -43,8 +44,8 @@ public class IncognitoUser extends MPUser<IncognitoSite> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MPMasterKey.Version getAlgorithmVersion() {
|
public MPAlgorithm getAlgorithm() {
|
||||||
return MPMasterKey.Version.CURRENT;
|
return MPMasterKey.Version.CURRENT.getAlgorithm();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,6 +31,8 @@ import javax.swing.border.CompoundBorder;
|
|||||||
*/
|
*/
|
||||||
public abstract class Components {
|
public abstract class Components {
|
||||||
|
|
||||||
|
public static final float CONTROL_TEXT_SIZE = 12f;
|
||||||
|
|
||||||
public static GradientPanel boxLayout(final int axis, final Component... components) {
|
public static GradientPanel boxLayout(final int axis, final Component... components) {
|
||||||
GradientPanel container = gradientPanel( null, null );
|
GradientPanel container = gradientPanel( null, null );
|
||||||
// container.setBackground( Color.red );
|
// container.setBackground( Color.red );
|
||||||
@ -73,7 +75,7 @@ public abstract class Components {
|
|||||||
{
|
{
|
||||||
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
||||||
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
|
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
|
||||||
setFont( Res.valueFont().deriveFont( 12f ) );
|
setFont( Res.valueFont().deriveFont( CONTROL_TEXT_SIZE ) );
|
||||||
setAlignmentX( LEFT_ALIGNMENT );
|
setAlignmentX( LEFT_ALIGNMENT );
|
||||||
setAlignmentY( BOTTOM_ALIGNMENT );
|
setAlignmentY( BOTTOM_ALIGNMENT );
|
||||||
}
|
}
|
||||||
@ -104,7 +106,7 @@ public abstract class Components {
|
|||||||
public static JButton button(final String label) {
|
public static JButton button(final String label) {
|
||||||
return new JButton( label ) {
|
return new JButton( label ) {
|
||||||
{
|
{
|
||||||
setFont( Res.controlFont().deriveFont( 12f ) );
|
setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
|
||||||
setAlignmentX( LEFT_ALIGNMENT );
|
setAlignmentX( LEFT_ALIGNMENT );
|
||||||
setAlignmentY( BOTTOM_ALIGNMENT );
|
setAlignmentY( BOTTOM_ALIGNMENT );
|
||||||
}
|
}
|
||||||
@ -160,7 +162,7 @@ public abstract class Components {
|
|||||||
public static JLabel label(@Nullable final String label, final int horizontalAlignment) {
|
public static JLabel label(@Nullable final String label, final int horizontalAlignment) {
|
||||||
return new JLabel( label, horizontalAlignment ) {
|
return new JLabel( label, horizontalAlignment ) {
|
||||||
{
|
{
|
||||||
setFont( Res.controlFont().deriveFont( 12f ) );
|
setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
|
||||||
setAlignmentX( LEFT_ALIGNMENT );
|
setAlignmentX( LEFT_ALIGNMENT );
|
||||||
setAlignmentY( BOTTOM_ALIGNMENT );
|
setAlignmentY( BOTTOM_ALIGNMENT );
|
||||||
}
|
}
|
||||||
@ -175,7 +177,7 @@ public abstract class Components {
|
|||||||
public static JCheckBox checkBox(final String label) {
|
public static JCheckBox checkBox(final String label) {
|
||||||
return new JCheckBox( label ) {
|
return new JCheckBox( label ) {
|
||||||
{
|
{
|
||||||
setFont( Res.controlFont().deriveFont( 12f ) );
|
setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
|
||||||
setBackground( null );
|
setBackground( null );
|
||||||
setAlignmentX( LEFT_ALIGNMENT );
|
setAlignmentX( LEFT_ALIGNMENT );
|
||||||
setAlignmentY( BOTTOM_ALIGNMENT );
|
setAlignmentY( BOTTOM_ALIGNMENT );
|
||||||
@ -195,7 +197,7 @@ public abstract class Components {
|
|||||||
// BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
// BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
|
||||||
// BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) );
|
// BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) );
|
||||||
// ((JComponent) ((BasicComboBoxEditor) getEditor()).getEditorComponent()).setBorder(editorBorder);
|
// ((JComponent) ((BasicComboBoxEditor) getEditor()).getEditorComponent()).setBorder(editorBorder);
|
||||||
setFont( Res.controlFont().deriveFont( 12f ) );
|
setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) );
|
||||||
setAlignmentX( LEFT_ALIGNMENT );
|
setAlignmentX( LEFT_ALIGNMENT );
|
||||||
setAlignmentY( BOTTOM_ALIGNMENT );
|
setAlignmentY( BOTTOM_ALIGNMENT );
|
||||||
// setBorder(null);
|
// setBorder(null);
|
||||||
|
@ -27,6 +27,8 @@ import javax.swing.*;
|
|||||||
*/
|
*/
|
||||||
public class UnsignedIntegerModel extends SpinnerNumberModel {
|
public class UnsignedIntegerModel extends SpinnerNumberModel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public UnsignedIntegerModel() {
|
public UnsignedIntegerModel() {
|
||||||
this( UnsignedInteger.ZERO, UnsignedInteger.ZERO, UnsignedInteger.MAX_VALUE, UnsignedInteger.ONE );
|
this( UnsignedInteger.ZERO, UnsignedInteger.ZERO, UnsignedInteger.MAX_VALUE, UnsignedInteger.ONE );
|
||||||
}
|
}
|
||||||
@ -43,6 +45,7 @@ public class UnsignedIntegerModel extends SpinnerNumberModel {
|
|||||||
this( value, minimum, maximum, UnsignedInteger.ONE );
|
this( value, minimum, maximum, UnsignedInteger.ONE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("TypeMayBeWeakened")
|
||||||
public UnsignedIntegerModel(final UnsignedInteger value, final UnsignedInteger minimum, final UnsignedInteger maximum,
|
public UnsignedIntegerModel(final UnsignedInteger value, final UnsignedInteger minimum, final UnsignedInteger maximum,
|
||||||
final UnsignedInteger stepSize) {
|
final UnsignedInteger stepSize) {
|
||||||
super( value, minimum, maximum, stepSize );
|
super( value, minimum, maximum, stepSize );
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword.gui.view;
|
package com.lyndir.masterpassword.gui.view;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.*;
|
||||||
import com.lyndir.masterpassword.MPResultType;
|
|
||||||
import com.lyndir.masterpassword.gui.Res;
|
import com.lyndir.masterpassword.gui.Res;
|
||||||
import com.lyndir.masterpassword.gui.model.IncognitoSite;
|
import com.lyndir.masterpassword.gui.model.IncognitoSite;
|
||||||
import com.lyndir.masterpassword.gui.model.IncognitoUser;
|
import com.lyndir.masterpassword.gui.model.IncognitoUser;
|
||||||
@ -29,6 +29,7 @@ import java.awt.*;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
@ -81,16 +82,17 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel<IncognitoU
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PasswordFrame<IncognitoUser, ?> newPasswordFrame() {
|
public PasswordFrame<IncognitoUser, ?> newPasswordFrame() {
|
||||||
return new PasswordFrame<IncognitoUser, IncognitoSite>( getSelectedUser() ) {
|
return new PasswordFrame<IncognitoUser, IncognitoSite>( Preconditions.checkNotNull( getSelectedUser() ) ) {
|
||||||
@Override
|
@Override
|
||||||
protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
|
protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPResultType resultType,
|
final MPResultType resultType,
|
||||||
final MPMasterKey.Version algorithmVersion) {
|
final MPAlgorithm algorithm) {
|
||||||
return new IncognitoSite( siteName, siteCounter, resultType, algorithmVersion );
|
return new IncognitoSite( siteName, siteCounter, resultType, algorithm );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected IncognitoUser getSelectedUser() {
|
protected IncognitoUser getSelectedUser() {
|
||||||
return new IncognitoUser( fullNameField.getText() );
|
return new IncognitoUser( fullNameField.getText() );
|
||||||
|
@ -23,14 +23,14 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.masterpassword.MPMasterKey;
|
import com.lyndir.masterpassword.*;
|
||||||
import com.lyndir.masterpassword.MPResultType;
|
|
||||||
import com.lyndir.masterpassword.gui.Res;
|
import com.lyndir.masterpassword.gui.Res;
|
||||||
import com.lyndir.masterpassword.gui.util.Components;
|
import com.lyndir.masterpassword.gui.util.Components;
|
||||||
import com.lyndir.masterpassword.model.*;
|
import com.lyndir.masterpassword.model.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
@ -71,7 +71,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
|
|||||||
add( userLabel );
|
add( userLabel );
|
||||||
|
|
||||||
userField = Components.comboBox( readConfigUsers() );
|
userField = Components.comboBox( readConfigUsers() );
|
||||||
userField.setFont( Res.valueFont().deriveFont( 12f ) );
|
userField.setFont( Res.valueFont().deriveFont( userField.getFont().getSize2D() ) );
|
||||||
userField.addItemListener( this );
|
userField.addItemListener( this );
|
||||||
userField.addActionListener( this );
|
userField.addActionListener( this );
|
||||||
userField.setRenderer( new DefaultListCellRenderer() {
|
userField.setRenderer( new DefaultListCellRenderer() {
|
||||||
@ -128,6 +128,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
|
|||||||
super.updateUser( repack );
|
super.updateUser( repack );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
protected MPFileUser getSelectedUser() {
|
protected MPFileUser getSelectedUser() {
|
||||||
int selectedIndex = userField.getSelectedIndex();
|
int selectedIndex = userField.getSelectedIndex();
|
||||||
@ -210,8 +211,8 @@ public class ModelAuthenticationPanel extends AuthenticationPanel<MPFileUser> im
|
|||||||
@Override
|
@Override
|
||||||
protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter,
|
protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPResultType resultType,
|
final MPResultType resultType,
|
||||||
final MPMasterKey.Version algorithmVersion) {
|
final MPAlgorithm algorithm) {
|
||||||
return new MPFileSite( user, siteName, siteCounter, resultType, algorithmVersion );
|
return new MPFileSite( user, siteName, siteCounter, resultType, algorithm );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import com.lyndir.masterpassword.gui.util.UnsignedIntegerModel;
|
|||||||
import com.lyndir.masterpassword.model.*;
|
import com.lyndir.masterpassword.model.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
import java.awt.datatransfer.Transferable;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -65,7 +66,8 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
private S currentSite;
|
private S currentSite;
|
||||||
private boolean updatingUI;
|
private boolean updatingUI;
|
||||||
|
|
||||||
public PasswordFrame(final U user) {
|
@SuppressWarnings({ "MagicNumber", "OverridableMethodCallDuringObjectConstruction" })
|
||||||
|
protected PasswordFrame(final U user) {
|
||||||
super( "Master Password" );
|
super( "Master Password" );
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
@ -97,7 +99,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
Futures.addCallback( updatePassword( true ), new FutureCallback<String>() {
|
Futures.addCallback( updatePassword( true ), new FutureCallback<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@Nullable final String sitePassword) {
|
public void onSuccess(@Nullable final String sitePassword) {
|
||||||
StringSelection clipboardContents = new StringSelection( sitePassword );
|
Transferable clipboardContents = new StringSelection( sitePassword );
|
||||||
Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null );
|
Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null );
|
||||||
|
|
||||||
SwingUtilities.invokeLater( new Runnable() {
|
SwingUtilities.invokeLater( new Runnable() {
|
||||||
@ -112,7 +114,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(final Throwable t) {
|
public void onFailure(@Nonnull final Throwable t) {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@ -144,8 +146,8 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
Components.stud(), //
|
Components.stud(), //
|
||||||
siteCounterField = Components.spinner( siteCounterModel ) );
|
siteCounterField = Components.spinner( siteCounterModel ) );
|
||||||
sitePanel.add( siteSettings );
|
sitePanel.add( siteSettings );
|
||||||
resultTypeField.setFont( Res.valueFont().deriveFont( 12f ) );
|
resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) );
|
||||||
resultTypeField.setSelectedItem( MPAlgorithm.mpw_default_type );
|
resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_type() );
|
||||||
resultTypeField.addItemListener( new ItemListener() {
|
resultTypeField.addItemListener( new ItemListener() {
|
||||||
@Override
|
@Override
|
||||||
public void itemStateChanged(final ItemEvent e) {
|
public void itemStateChanged(final ItemEvent e) {
|
||||||
@ -153,9 +155,9 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
siteVersionField.setFont( Res.valueFont().deriveFont( 12f ) );
|
siteVersionField.setFont( Res.valueFont().deriveFont( siteVersionField.getFont().getSize2D() ) );
|
||||||
siteVersionField.setAlignmentX( RIGHT_ALIGNMENT );
|
siteVersionField.setAlignmentX( RIGHT_ALIGNMENT );
|
||||||
siteVersionField.setSelectedItem( user.getAlgorithmVersion() );
|
siteVersionField.setSelectedItem( user.getAlgorithm() );
|
||||||
siteVersionField.addItemListener( new ItemListener() {
|
siteVersionField.addItemListener( new ItemListener() {
|
||||||
@Override
|
@Override
|
||||||
public void itemStateChanged(final ItemEvent e) {
|
public void itemStateChanged(final ItemEvent e) {
|
||||||
@ -163,7 +165,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
siteCounterField.setFont( Res.valueFont().deriveFont( 12f ) );
|
siteCounterField.setFont( Res.valueFont().deriveFont( siteCounterField.getFont().getSize2D() ) );
|
||||||
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
|
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
|
||||||
siteCounterField.addChangeListener( new ChangeListener() {
|
siteCounterField.addChangeListener( new ChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -186,7 +188,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
// Password
|
// Password
|
||||||
passwordField = Components.passwordField();
|
passwordField = Components.passwordField();
|
||||||
passwordField.setAlignmentX( Component.CENTER_ALIGNMENT );
|
passwordField.setAlignmentX( Component.CENTER_ALIGNMENT );
|
||||||
passwordField.setHorizontalAlignment( JTextField.CENTER );
|
passwordField.setHorizontalAlignment( SwingConstants.CENTER );
|
||||||
passwordField.putClientProperty( "JPasswordField.cutCopyAllowed", true );
|
passwordField.putClientProperty( "JPasswordField.cutCopyAllowed", true );
|
||||||
passwordField.setEditable( false );
|
passwordField.setEditable( false );
|
||||||
passwordField.setBackground( null );
|
passwordField.setBackground( null );
|
||||||
@ -215,6 +217,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
setLocationRelativeTo( null );
|
setLocationRelativeTo( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("MagicNumber")
|
||||||
private void updateMask() {
|
private void updateMask() {
|
||||||
passwordField.setEchoChar( maskPasswordField.isSelected()? passwordEchoChar: (char) 0 );
|
passwordField.setEchoChar( maskPasswordField.isSelected()? passwordEchoChar: (char) 0 );
|
||||||
passwordField.setFont( maskPasswordField.isSelected()? passwordEchoFont: Res.bigValueFont().deriveFont( 40f ) );
|
passwordField.setFont( maskPasswordField.isSelected()? passwordEchoFont: Res.bigValueFont().deriveFont( 40f ) );
|
||||||
@ -233,9 +236,9 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
return Futures.immediateCancelledFuture();
|
return Futures.immediateCancelledFuture();
|
||||||
}
|
}
|
||||||
|
|
||||||
MPResultType resultType = resultTypeField.getModel().getElementAt( resultTypeField.getSelectedIndex() );
|
MPResultType resultType = resultTypeField.getModel().getElementAt( resultTypeField.getSelectedIndex() );
|
||||||
MPMasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() );
|
MPAlgorithm siteAlgorithm = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() ).getAlgorithm();
|
||||||
UnsignedInteger siteCounter = siteCounterModel.getNumber();
|
UnsignedInteger siteCounter = siteCounterModel.getNumber();
|
||||||
|
|
||||||
Iterable<S> siteResults = user.findSites( siteNameQuery );
|
Iterable<S> siteResults = user.findSites( siteNameQuery );
|
||||||
if (!allowNameCompletion)
|
if (!allowNameCompletion)
|
||||||
@ -246,10 +249,10 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
final S site = ifNotNullElse( Iterables.getFirst( siteResults, null ),
|
final S site = ifNotNullElse( Iterables.getFirst( siteResults, null ),
|
||||||
createSite( user, siteNameQuery, siteCounter, resultType, siteVersion ) );
|
createSite( user, siteNameQuery, siteCounter, resultType, siteAlgorithm ) );
|
||||||
if ((currentSite != null) && currentSite.getSiteName().equals( site.getSiteName() )) {
|
if ((currentSite != null) && currentSite.getSiteName().equals( site.getSiteName() )) {
|
||||||
site.setResultType( resultType );
|
site.setResultType( resultType );
|
||||||
site.setAlgorithmVersion( siteVersion );
|
site.setAlgorithm( siteAlgorithm );
|
||||||
site.setSiteCounter( siteCounter );
|
site.setSiteCounter( siteCounter );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +262,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
return user.getMasterKey()
|
return user.getMasterKey()
|
||||||
.siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Authentication, null, site.getResultType(),
|
.siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Authentication, null, site.getResultType(),
|
||||||
null, site.getAlgorithmVersion() );
|
null, site.getAlgorithm() );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
Futures.addCallback( passwordFuture, new FutureCallback<String>() {
|
Futures.addCallback( passwordFuture, new FutureCallback<String>() {
|
||||||
@ -276,7 +279,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
else
|
else
|
||||||
siteActionButton.setText( "Add Site" );
|
siteActionButton.setText( "Add Site" );
|
||||||
resultTypeField.setSelectedItem( currentSite.getResultType() );
|
resultTypeField.setSelectedItem( currentSite.getResultType() );
|
||||||
siteVersionField.setSelectedItem( currentSite.getAlgorithmVersion() );
|
siteVersionField.setSelectedItem( currentSite.getAlgorithm() );
|
||||||
siteCounterField.setValue( currentSite.getSiteCounter() );
|
siteCounterField.setValue( currentSite.getSiteCounter() );
|
||||||
siteNameField.setText( currentSite.getSiteName() );
|
siteNameField.setText( currentSite.getSiteName() );
|
||||||
if (siteNameField.getText().startsWith( siteNameQuery ))
|
if (siteNameField.getText().startsWith( siteNameQuery ))
|
||||||
@ -290,15 +293,14 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(final Throwable t) {
|
public void onFailure(@Nonnull final Throwable t) {
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
return passwordFuture;
|
return passwordFuture;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract S createSite(U user, String siteName, UnsignedInteger siteCounter, MPResultType resultType,
|
protected abstract S createSite(U user, String siteName, UnsignedInteger siteCounter, MPResultType resultType, MPAlgorithm algorithm);
|
||||||
MPMasterKey.Version algorithmVersion);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void insertUpdate(final DocumentEvent e) {
|
public void insertUpdate(final DocumentEvent e) {
|
||||||
|
@ -21,10 +21,10 @@ package com.lyndir.masterpassword.gui.view;
|
|||||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||||
|
|
||||||
import com.lyndir.masterpassword.MPIdenticon;
|
import com.lyndir.masterpassword.MPIdenticon;
|
||||||
import com.lyndir.masterpassword.gui.Res;
|
import com.lyndir.masterpassword.gui.*;
|
||||||
|
import com.lyndir.masterpassword.model.MPUser;
|
||||||
import com.lyndir.masterpassword.gui.util.Components;
|
import com.lyndir.masterpassword.gui.util.Components;
|
||||||
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
|
import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException;
|
||||||
import com.lyndir.masterpassword.model.MPUser;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -196,7 +196,7 @@ public class UnlockFrame extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void trySignIn(final JComponent... signInComponents) {
|
void trySignIn(final JComponent... signInComponents) {
|
||||||
if (!checkSignIn())
|
if ((user == null) || !checkSignIn())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (final JComponent signInComponent : signInComponents)
|
for (final JComponent signInComponent : signInComponents)
|
||||||
|
@ -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-04-26
|
||||||
|
*/
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package com.lyndir.masterpassword.gui.view;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
Loading…
Reference in New Issue
Block a user