diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java index c5021ef4..83736863 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithm.java @@ -30,89 +30,102 @@ import javax.annotation.Nullable; /** * @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. */ - MPResultType mpw_default_type = MPResultType.GeneratedLong; + public abstract MPResultType mpw_default_type(); /** * 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. */ - MessageDigests mpw_hash = MessageDigests.SHA256; + public abstract MessageDigests mpw_hash(); /** * mpw: Site digest. */ - MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256; + public abstract MessageAuthenticationDigests mpw_digest(); /** * mpw: Platform-agnostic byte order. */ - ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN; + public abstract ByteOrder mpw_byteOrder(); /** * mpw: Input character encoding. */ - Charset mpw_charset = Charsets.UTF_8; + public abstract Charset mpw_charset(); /** * 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. */ - int scrypt_p = 2; + public abstract int scrypt_p(); /** * scrypt: Memory cost parameter. */ - int scrypt_r = 8; + public abstract int scrypt_r(); /** * scrypt: CPU cost parameter. */ - int scrypt_N = 32768; - - 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); + public abstract int scrypt_N(); // 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); } diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java index c9d0835e..c0cf5106 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV0.java @@ -18,17 +18,16 @@ package com.lyndir.masterpassword; -import com.google.common.base.Preconditions; -import com.google.common.base.Throwables; +import com.google.common.base.*; import com.google.common.primitives.Bytes; import com.google.common.primitives.UnsignedInteger; import com.lambdaworks.crypto.SCrypt; 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.util.ConversionUtils; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; +import java.nio.*; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.util.Arrays; import javax.annotation.Nullable; @@ -40,20 +39,17 @@ import javax.crypto.IllegalBlockSizeException; * @author lhunath, 2014-08-30 * @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() ); - @Override - public MPMasterKey.Version getAlgorithmVersion() { - - return MPMasterKey.Version.V0; - } - @Override 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() ); String keyScope = MPKeyPurpose.Authentication.getScope(); @@ -62,12 +58,12 @@ public class MPAlgorithmV0 implements MPAlgorithm { // Calculate the master key salt. logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s", 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 ) ) ); // Calculate the master key. 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[] masterKey = scrypt( masterKeySalt, masterPasswordBytes ); Arrays.fill( masterKeySalt, (byte) 0 ); @@ -79,7 +75,7 @@ public class MPAlgorithmV0 implements MPAlgorithm { protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) { 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) { throw logger.bug( e ); @@ -95,25 +91,25 @@ public class MPAlgorithmV0 implements MPAlgorithm { // OTP counter value. 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. - byte[] siteNameBytes = siteName.getBytes( mpw_charset ); + byte[] siteNameBytes = siteName.getBytes( mpw_charset() ); byte[] siteNameLengthBytes = toBytes( siteName.length() ); 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 ); logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s", keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), (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) sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes ); logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) ); 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 ) ) ); return sitePasswordSeedBytes; @@ -142,7 +138,7 @@ public class MPAlgorithmV0 implements MPAlgorithm { int[] _siteKey = new int[siteKey.length]; 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) ); buf.position( 2 ); buf.put( siteKey[i] ).rewind(); @@ -185,7 +181,7 @@ public class MPAlgorithmV0 implements MPAlgorithm { // Decrypt 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 ) ); return plainText; @@ -202,14 +198,14 @@ public class MPAlgorithmV0 implements MPAlgorithm { if (resultType == MPResultType.DeriveKey) { int resultParamInt = ConversionUtils.toIntegerNN( resultParam ); if (resultParamInt == 0) - resultParamInt = 512; - if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0)) + resultParamInt = mpw_keySize_max(); + 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 ); int keySize = resultParamInt / 8; logger.trc( "keySize: %d", keySize ); // 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) throw logger.bug( "Could not derive result key." ); @@ -229,7 +225,7 @@ public class MPAlgorithmV0 implements MPAlgorithm { try { // 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 ) ); // 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 @Override 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 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 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()]; byteBuffer.get( bytes ); @@ -268,6 +382,6 @@ public class MPAlgorithmV0 implements MPAlgorithm { @Override public byte[] toID(final byte[] bytes) { - return mpw_hash.of( bytes ); + return mpw_hash().of( bytes ); } } diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV1.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV1.java index 9d92dfd5..cfb98ebe 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV1.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV1.java @@ -29,12 +29,6 @@ import javax.annotation.Nullable; */ public class MPAlgorithmV1 extends MPAlgorithmV0 { - @Override - public MPMasterKey.Version getAlgorithmVersion() { - - return MPMasterKey.Version.V1; - } - @Override public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) { @@ -60,4 +54,11 @@ public class MPAlgorithmV1 extends MPAlgorithmV0 { return password.toString(); } + + // Configuration + + @Override + public MPMasterKey.Version version() { + return MPMasterKey.Version.V1; + } } diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV2.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV2.java index 581c0c73..4ccdee7b 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV2.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV2.java @@ -30,12 +30,6 @@ import javax.annotation.Nullable; */ public class MPAlgorithmV2 extends MPAlgorithmV1 { - @Override - public MPMasterKey.Version getAlgorithmVersion() { - - return MPMasterKey.Version.V2; - } - @Override public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose, @Nullable final String keyContext) { @@ -45,27 +39,34 @@ public class MPAlgorithmV2 extends MPAlgorithmV1 { // OTP counter value. 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. - byte[] siteNameBytes = siteName.getBytes( mpw_charset ); + byte[] siteNameBytes = siteName.getBytes( mpw_charset() ); byte[] siteNameLengthBytes = toBytes( siteNameBytes.length ); 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 ); logger.trc( "siteSalt: keyScope=%s | #siteName=%s | siteName=%s | siteCounter=%s | #keyContext=%s | keyContext=%s", keyScope, CodeUtils.encodeHex( siteNameLengthBytes ), siteName, CodeUtils.encodeHex( siteCounterBytes ), (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) sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes ); logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) ); 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 ) ) ); return sitePasswordSeedBytes; } + + // Configuration + + @Override + public MPMasterKey.Version version() { + return MPMasterKey.Version.V2; + } } diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV3.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV3.java index 5c90bcfa..e951bab9 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV3.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPAlgorithmV3.java @@ -29,16 +29,10 @@ import java.util.Arrays; */ public class MPAlgorithmV3 extends MPAlgorithmV2 { - @Override - public MPMasterKey.Version getAlgorithmVersion() { - - return MPMasterKey.Version.V3; - } - @Override 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 ); String keyScope = MPKeyPurpose.Authentication.getScope(); @@ -47,12 +41,12 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 { // Calculate the master key salt. logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s", 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 ) ) ); // Calculate the master key. 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[] masterKey = scrypt( masterKeySalt, mpBytes ); Arrays.fill( masterKeySalt, (byte) 0 ); @@ -61,4 +55,11 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 { return masterKey; } + + // Configuration + + @Override + public MPMasterKey.Version version() { + return MPMasterKey.Version.V3; + } } diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPIdenticon.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPIdenticon.java index 29b19b0e..d08940cb 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPIdenticon.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPIdenticon.java @@ -21,6 +21,8 @@ package com.lyndir.masterpassword; import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.google.common.base.Charsets; +import com.google.common.primitives.UnsignedBytes; +import com.google.common.primitives.UnsignedInteger; import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests; import com.lyndir.lhunath.opal.system.logging.Logger; import java.nio.*; @@ -66,7 +68,7 @@ public class MPIdenticon { IntBuffer identiconSeedBuffer = IntBuffer.allocate( identiconSeedBytes.capacity() ); while (identiconSeedBytes.hasRemaining()) - identiconSeedBuffer.put( identiconSeedBytes.get() & 0xFF ); + identiconSeedBuffer.put( UnsignedBytes.toInt( identiconSeedBytes.get() ) ); int[] identiconSeed = identiconSeedBuffer.array(); color = colors[identiconSeed[4] % colors.length]; diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java index bd87b9f2..4a8fd464 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPMasterKey.java @@ -58,21 +58,21 @@ public class MPMasterKey { * * @throws MPInvalidatedException {@link #invalidate()} has been called on this object. */ - private byte[] masterKey(final Version algorithmVersion) + private byte[] masterKey(final MPAlgorithm algorithm) throws MPInvalidatedException { Preconditions.checkArgument( masterPassword.length > 0 ); if (invalidated) throw new MPInvalidatedException(); - byte[] key = keyByVersion.get( algorithmVersion ); + byte[] key = keyByVersion.get( algorithm.version() ); 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( "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; @@ -84,19 +84,19 @@ public class MPMasterKey { * @throws MPInvalidatedException {@link #invalidate()} has been called on this object. */ 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 { 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( "siteCounter: %s", siteCounter ); logger.trc( "keyPurpose: %d (%s)", keyPurpose.toInt(), keyPurpose.getShortName() ); 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 resultType The type of result to generate. * @param resultParam A parameter for the resultType. For stateful result types, the output of - * {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}. + * {@link #siteState(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}. * * @throws MPInvalidatedException {@link #invalidate()} has been called on this object. */ public String siteResult(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose, @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam, - final Version algorithmVersion) + final MPAlgorithm algorithm) throws MPInvalidatedException { - byte[] masterKey = masterKey( algorithmVersion ); - byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion ); + byte[] masterKey = masterKey( algorithm ); + 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( "resultParam: %s", resultParam ); - return algorithmVersion.getAlgorithm().siteResult( + return algorithm.siteResult( masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam ); } @@ -137,26 +137,26 @@ public class MPMasterKey { * @param keyContext A site-scoped key modifier. * @param resultType The type of result token to encrypt. * @param resultParam The result token desired from - * {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, Version)}. + * {@link #siteResult(String, UnsignedInteger, MPKeyPurpose, String, MPResultType, String, MPAlgorithm)}. * * @throws MPInvalidatedException {@link #invalidate()} has been called on this object. */ public String siteState(final String siteName, final UnsignedInteger siteCounter, final MPKeyPurpose keyPurpose, @Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam, - final Version algorithmVersion) + final MPAlgorithm algorithm) throws MPInvalidatedException { Preconditions.checkNotNull( resultParam ); Preconditions.checkArgument( !resultParam.isEmpty() ); - byte[] masterKey = masterKey( algorithmVersion ); - byte[] siteKey = siteKey( siteName, siteCounter, keyPurpose, keyContext, algorithmVersion ); + byte[] masterKey = masterKey( algorithm ); + 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( "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 ); } @@ -171,10 +171,10 @@ public class MPMasterKey { * * @throws MPInvalidatedException {@link #invalidate()} has been called on this object. */ - public byte[] getKeyID(final Version algorithmVersion) + public byte[] getKeyID(final MPAlgorithm algorithm) throws MPInvalidatedException { - return algorithmVersion.getAlgorithm().toID( masterKey( algorithmVersion ) ); + return algorithm.toID( masterKey( algorithm ) ); } /** diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java index 5e844ebb..d70a2091 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/MPResultType.java @@ -31,6 +31,7 @@ import org.jetbrains.annotations.Contract; * * @author lhunath */ +@SuppressWarnings("RedundantTypeArguments" /* IDEA-191043 */) public enum MPResultType { // bit 0-3 | MPResultTypeClass | MPSiteFeature @@ -134,7 +135,7 @@ public enum MPResultType { private final List templates; private final MPResultTypeClass typeClass; private final int typeIndex; - private final Set typeFeatures; + private final ImmutableSet typeFeatures; MPResultType(final String shortName, final String description, final List templates, final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) { @@ -166,7 +167,8 @@ public enum MPResultType { return typeClass; } - public Set getTypeFeatures() { + @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType" /* IDEA-191042 */ ) + public ImmutableSet getTypeFeatures() { return typeFeatures; } @@ -232,6 +234,7 @@ public enum MPResultType { * * @return All types that support the given mask's class & features. */ + @SuppressWarnings({ "MagicNumber", "UnnecessaryParentheses" /* IDEA-191040 */ }) public static ImmutableList forMask(final int mask) { int typeMask = mask & ~0xF; // Ignore resultType bit 0-3 diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java index 3fbd35a7..a2251d86 100644 --- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java +++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileSite.java @@ -35,7 +35,7 @@ public class MPFileSite extends MPSite { private String siteContent; private UnsignedInteger siteCounter; private MPResultType resultType; - private MPMasterKey.Version algorithmVersion; + private MPAlgorithm algorithm; @Nullable private String loginContent; @@ -49,24 +49,24 @@ public class MPFileSite extends MPSite { public MPFileSite(final MPFileUser user, final String siteName) { this( user, siteName, - user.getAlgorithmVersion().getAlgorithm().mpw_default_counter, - user.getAlgorithmVersion().getAlgorithm().mpw_default_type, - user.getAlgorithmVersion() ); + user.getAlgorithm().mpw_default_counter(), + user.getAlgorithm().mpw_default_type(), + user.getAlgorithm() ); } 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.siteName = siteName; this.siteCounter = siteCounter; this.resultType = resultType; - this.algorithmVersion = algorithmVersion; + this.algorithm = algorithm; this.lastUsed = new Instant(); } protected MPFileSite(final MPFileUser user, final String siteName, @Nullable final String siteContent, 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 url, final int uses, final Instant lastUsed) { this.user = user; @@ -74,7 +74,7 @@ public class MPFileSite extends MPSite { this.siteContent = siteContent; this.siteCounter = siteCounter; this.resultType = resultType; - this.algorithmVersion = algorithmVersion; + this.algorithm = algorithm; this.loginContent = loginContent; this.loginType = loginType; this.url = url; @@ -129,7 +129,7 @@ public class MPFileSite extends MPSite { this.siteContent = null; else this.siteContent = masterKey.siteState( - getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, getAlgorithmVersion() ); + getSiteName(), getSiteCounter(), MPKeyPurpose.Authentication, null, getResultType(), result, algorithm ); } @Override @@ -153,13 +153,13 @@ public class MPFileSite extends MPSite { } @Override - public MPMasterKey.Version getAlgorithmVersion() { - return algorithmVersion; + public MPAlgorithm getAlgorithm() { + return algorithm; } @Override - public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) { - this.algorithmVersion = algorithmVersion; + public void setAlgorithm(final MPAlgorithm algorithm) { + this.algorithm = algorithm; } @Nullable @@ -180,8 +180,8 @@ public class MPFileSite extends MPSite { this.loginContent = null; else this.loginContent = masterKey.siteState( - siteName, MPAlgorithm.mpw_default_counter, MPKeyPurpose.Identification, null, this.loginType, result, - algorithmVersion ); + siteName, algorithm.mpw_default_counter(), MPKeyPurpose.Identification, null, this.loginType, result, + algorithm ); } @Nullable diff --git a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java index d88c83af..424a47c4 100755 --- a/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java +++ b/core/java/model/src/main/java/com/lyndir/masterpassword/model/MPFileUser.java @@ -22,8 +22,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.lyndir.lhunath.opal.system.logging.Logger; import com.lyndir.masterpassword.*; -import java.util.Arrays; -import java.util.Collection; +import java.util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.joda.time.Instant; @@ -43,7 +42,7 @@ public class MPFileUser extends MPUser implements Comparable implements Comparable implements Comparable implements Comparable getSites() { - return sites; + return Collections.unmodifiableCollection( sites ); } @Override @@ -158,8 +157,8 @@ public class MPFileUser extends MPUser implements Comparable { public String exportKeyID() 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() { return 0; diff --git a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java index 0cec07e1..b9895b37 100644 --- a/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java +++ b/core/java/tests/src/main/java/com/lyndir/masterpassword/MPTests.java @@ -171,8 +171,8 @@ public class MPTests { } @Nonnull - public MPMasterKey.Version getAlgorithm() { - return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) ); + public MPAlgorithm getAlgorithm() { + return MPMasterKey.Version.fromInt( checkNotNull( algorithm ) ).getAlgorithm(); } @Nonnull diff --git a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java index 2da9be97..d689619f 100644 --- a/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java +++ b/core/java/tests/src/test/java/com/lyndir/masterpassword/MPMasterKeyTest.java @@ -109,14 +109,15 @@ public class MPMasterKeyTest { MPMasterKey masterKey = new MPMasterKey( testCase.getFullName(), masterPassword ); String password = randomString( 8 ); + MPResultType resultType = MPResultType.StoredPersonal; for (final MPMasterKey.Version version : MPMasterKey.Version.values()) { - MPResultType resultType = MPResultType.StoredPersonal; + MPAlgorithm algorithm = version.getAlgorithm(); // Test site state 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(), - testCase.getKeyContext(), resultType, state, version ); + testCase.getKeyContext(), resultType, state, algorithm ); assertEquals( result, diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java index a10631fc..07f8a96a 100644 --- a/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java +++ b/platform-android/src/main/java/com/lyndir/masterpassword/EmergencyActivity.java @@ -303,7 +303,7 @@ public class EmergencyActivity extends Activity { @Override public void run() { 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() { @Override diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java index 01ed31e5..29e103c6 100644 --- a/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java +++ b/platform-android/src/main/java/com/lyndir/masterpassword/Preferences.java @@ -148,7 +148,7 @@ public final class Preferences { @Nonnull 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) { diff --git a/platform-android/src/main/java/com/lyndir/masterpassword/TestActivity.java b/platform-android/src/main/java/com/lyndir/masterpassword/TestActivity.java index 26ebf069..c82dda30 100644 --- a/platform-android/src/main/java/com/lyndir/masterpassword/TestActivity.java +++ b/platform-android/src/main/java/com/lyndir/masterpassword/TestActivity.java @@ -38,6 +38,7 @@ import java.util.concurrent.Executors; import javax.annotation.Nullable; +@SuppressWarnings("PublicMethodNotExposedInInterface" /* IDEA-191044 */) public class TestActivity extends Activity implements MPTestSuite.Listener { @SuppressWarnings("UnusedDeclaration") @@ -64,6 +65,7 @@ public class TestActivity extends Activity implements MPTestSuite.Listener { private MPTestSuite testSuite; private ListenableFuture testFuture; + @Nullable private Runnable action; private ImmutableSet testNames; diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java index 7bf56fd8..e3815291 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoSite.java @@ -19,8 +19,7 @@ package com.lyndir.masterpassword.gui.model; import com.google.common.primitives.UnsignedInteger; -import com.lyndir.masterpassword.MPMasterKey; -import com.lyndir.masterpassword.MPResultType; +import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.model.MPSite; @@ -29,17 +28,17 @@ import com.lyndir.masterpassword.model.MPSite; */ public class IncognitoSite extends MPSite { - private String siteName; - private UnsignedInteger siteCounter; - private MPResultType resultType; - private MPMasterKey.Version algorithmVersion; + private String siteName; + private UnsignedInteger siteCounter; + private MPResultType resultType; + private MPAlgorithm algorithm; public IncognitoSite(final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType, - final MPMasterKey.Version algorithmVersion) { + final MPAlgorithm algorithm) { this.siteName = siteName; this.siteCounter = siteCounter; this.resultType = resultType; - this.algorithmVersion = algorithmVersion; + this.algorithm = algorithm; } @Override @@ -63,13 +62,13 @@ public class IncognitoSite extends MPSite { } @Override - public MPMasterKey.Version getAlgorithmVersion() { - return algorithmVersion; + public MPAlgorithm getAlgorithm() { + return algorithm; } @Override - public void setAlgorithmVersion(final MPMasterKey.Version algorithmVersion) { - this.algorithmVersion = algorithmVersion; + public void setAlgorithm(final MPAlgorithm algorithm) { + this.algorithm = algorithm; } @Override diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoUser.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoUser.java index 1aaa6216..8b7eccfe 100755 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoUser.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/model/IncognitoUser.java @@ -19,6 +19,7 @@ package com.lyndir.masterpassword.gui.model; import com.google.common.collect.ImmutableList; +import com.lyndir.masterpassword.MPAlgorithm; import com.lyndir.masterpassword.MPMasterKey; import com.lyndir.masterpassword.model.MPIncorrectMasterPasswordException; import com.lyndir.masterpassword.model.MPUser; @@ -43,8 +44,8 @@ public class IncognitoUser extends MPUser { } @Override - public MPMasterKey.Version getAlgorithmVersion() { - return MPMasterKey.Version.CURRENT; + public MPAlgorithm getAlgorithm() { + return MPMasterKey.Version.CURRENT.getAlgorithm(); } @Override diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/Components.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/Components.java index f2db4cb1..36898385 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/Components.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/Components.java @@ -31,6 +31,8 @@ import javax.swing.border.CompoundBorder; */ public abstract class Components { + public static final float CONTROL_TEXT_SIZE = 12f; + public static GradientPanel boxLayout(final int axis, final Component... components) { GradientPanel container = gradientPanel( null, null ); // container.setBackground( Color.red ); @@ -73,7 +75,7 @@ public abstract class Components { { setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ), BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) ); - setFont( Res.valueFont().deriveFont( 12f ) ); + setFont( Res.valueFont().deriveFont( CONTROL_TEXT_SIZE ) ); setAlignmentX( LEFT_ALIGNMENT ); setAlignmentY( BOTTOM_ALIGNMENT ); } @@ -104,7 +106,7 @@ public abstract class Components { public static JButton button(final String label) { return new JButton( label ) { { - setFont( Res.controlFont().deriveFont( 12f ) ); + setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) ); setAlignmentX( LEFT_ALIGNMENT ); setAlignmentY( BOTTOM_ALIGNMENT ); } @@ -160,7 +162,7 @@ public abstract class Components { public static JLabel label(@Nullable final String label, final int horizontalAlignment) { return new JLabel( label, horizontalAlignment ) { { - setFont( Res.controlFont().deriveFont( 12f ) ); + setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) ); setAlignmentX( LEFT_ALIGNMENT ); setAlignmentY( BOTTOM_ALIGNMENT ); } @@ -175,7 +177,7 @@ public abstract class Components { public static JCheckBox checkBox(final String label) { return new JCheckBox( label ) { { - setFont( Res.controlFont().deriveFont( 12f ) ); + setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) ); setBackground( null ); setAlignmentX( LEFT_ALIGNMENT ); setAlignmentY( BOTTOM_ALIGNMENT ); @@ -195,7 +197,7 @@ public abstract class Components { // BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ), // BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ); // ((JComponent) ((BasicComboBoxEditor) getEditor()).getEditorComponent()).setBorder(editorBorder); - setFont( Res.controlFont().deriveFont( 12f ) ); + setFont( Res.controlFont().deriveFont( CONTROL_TEXT_SIZE ) ); setAlignmentX( LEFT_ALIGNMENT ); setAlignmentY( BOTTOM_ALIGNMENT ); // setBorder(null); diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/UnsignedIntegerModel.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/UnsignedIntegerModel.java index 0d8a8400..ae2655e4 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/UnsignedIntegerModel.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/util/UnsignedIntegerModel.java @@ -27,6 +27,8 @@ import javax.swing.*; */ public class UnsignedIntegerModel extends SpinnerNumberModel { + private static final long serialVersionUID = 1L; + public UnsignedIntegerModel() { 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 ); } + @SuppressWarnings("TypeMayBeWeakened") public UnsignedIntegerModel(final UnsignedInteger value, final UnsignedInteger minimum, final UnsignedInteger maximum, final UnsignedInteger stepSize) { super( value, minimum, maximum, stepSize ); diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java index c04cbcf2..e8995f87 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/IncognitoAuthenticationPanel.java @@ -18,9 +18,9 @@ package com.lyndir.masterpassword.gui.view; +import com.google.common.base.Preconditions; import com.google.common.primitives.UnsignedInteger; -import com.lyndir.masterpassword.MPMasterKey; -import com.lyndir.masterpassword.MPResultType; +import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.model.IncognitoSite; import com.lyndir.masterpassword.gui.model.IncognitoUser; @@ -29,6 +29,7 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -81,16 +82,17 @@ public class IncognitoAuthenticationPanel extends AuthenticationPanel newPasswordFrame() { - return new PasswordFrame( getSelectedUser() ) { + return new PasswordFrame( Preconditions.checkNotNull( getSelectedUser() ) ) { @Override protected IncognitoSite createSite(final IncognitoUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType, - final MPMasterKey.Version algorithmVersion) { - return new IncognitoSite( siteName, siteCounter, resultType, algorithmVersion ); + final MPAlgorithm algorithm) { + return new IncognitoSite( siteName, siteCounter, resultType, algorithm ); } }; } + @Nullable @Override protected IncognitoUser getSelectedUser() { return new IncognitoUser( fullNameField.getText() ); diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/ModelAuthenticationPanel.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/ModelAuthenticationPanel.java index 17fb3284..1c5d8e03 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/ModelAuthenticationPanel.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/ModelAuthenticationPanel.java @@ -23,14 +23,14 @@ import static com.lyndir.lhunath.opal.system.util.StringUtils.*; import com.google.common.collect.ImmutableList; import com.google.common.primitives.UnsignedInteger; import com.lyndir.lhunath.opal.system.logging.Logger; -import com.lyndir.masterpassword.MPMasterKey; -import com.lyndir.masterpassword.MPResultType; +import com.lyndir.masterpassword.*; import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.model.*; import java.awt.*; import java.awt.event.*; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -71,7 +71,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel im add( userLabel ); userField = Components.comboBox( readConfigUsers() ); - userField.setFont( Res.valueFont().deriveFont( 12f ) ); + userField.setFont( Res.valueFont().deriveFont( userField.getFont().getSize2D() ) ); userField.addItemListener( this ); userField.addActionListener( this ); userField.setRenderer( new DefaultListCellRenderer() { @@ -128,6 +128,7 @@ public class ModelAuthenticationPanel extends AuthenticationPanel im super.updateUser( repack ); } + @Nullable @Override protected MPFileUser getSelectedUser() { int selectedIndex = userField.getSelectedIndex(); @@ -210,8 +211,8 @@ public class ModelAuthenticationPanel extends AuthenticationPanel im @Override protected MPFileSite createSite(final MPFileUser user, final String siteName, final UnsignedInteger siteCounter, final MPResultType resultType, - final MPMasterKey.Version algorithmVersion) { - return new MPFileSite( user, siteName, siteCounter, resultType, algorithmVersion ); + final MPAlgorithm algorithm) { + return new MPFileSite( user, siteName, siteCounter, resultType, algorithm ); } }; } diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java index 408a9072..7977b71d 100755 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/PasswordFrame.java @@ -33,6 +33,7 @@ import com.lyndir.masterpassword.gui.util.UnsignedIntegerModel; import com.lyndir.masterpassword.model.*; import java.awt.*; import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; import java.awt.event.*; import java.util.concurrent.Callable; import javax.annotation.Nonnull; @@ -65,7 +66,8 @@ public abstract class PasswordFrame, S extends MPSite> exten private S currentSite; private boolean updatingUI; - public PasswordFrame(final U user) { + @SuppressWarnings({ "MagicNumber", "OverridableMethodCallDuringObjectConstruction" }) + protected PasswordFrame(final U user) { super( "Master Password" ); this.user = user; @@ -97,7 +99,7 @@ public abstract class PasswordFrame, S extends MPSite> exten Futures.addCallback( updatePassword( true ), new FutureCallback() { @Override public void onSuccess(@Nullable final String sitePassword) { - StringSelection clipboardContents = new StringSelection( sitePassword ); + Transferable clipboardContents = new StringSelection( sitePassword ); Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null ); SwingUtilities.invokeLater( new Runnable() { @@ -112,7 +114,7 @@ public abstract class PasswordFrame, S extends MPSite> exten } @Override - public void onFailure(final Throwable t) { + public void onFailure(@Nonnull final Throwable t) { } } ); } @@ -144,8 +146,8 @@ public abstract class PasswordFrame, S extends MPSite> exten Components.stud(), // siteCounterField = Components.spinner( siteCounterModel ) ); sitePanel.add( siteSettings ); - resultTypeField.setFont( Res.valueFont().deriveFont( 12f ) ); - resultTypeField.setSelectedItem( MPAlgorithm.mpw_default_type ); + resultTypeField.setFont( Res.valueFont().deriveFont( resultTypeField.getFont().getSize2D() ) ); + resultTypeField.setSelectedItem( user.getAlgorithm().mpw_default_type() ); resultTypeField.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { @@ -153,9 +155,9 @@ public abstract class PasswordFrame, S extends MPSite> exten } } ); - siteVersionField.setFont( Res.valueFont().deriveFont( 12f ) ); + siteVersionField.setFont( Res.valueFont().deriveFont( siteVersionField.getFont().getSize2D() ) ); siteVersionField.setAlignmentX( RIGHT_ALIGNMENT ); - siteVersionField.setSelectedItem( user.getAlgorithmVersion() ); + siteVersionField.setSelectedItem( user.getAlgorithm() ); siteVersionField.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent e) { @@ -163,7 +165,7 @@ public abstract class PasswordFrame, S extends MPSite> exten } } ); - siteCounterField.setFont( Res.valueFont().deriveFont( 12f ) ); + siteCounterField.setFont( Res.valueFont().deriveFont( siteCounterField.getFont().getSize2D() ) ); siteCounterField.setAlignmentX( RIGHT_ALIGNMENT ); siteCounterField.addChangeListener( new ChangeListener() { @Override @@ -186,7 +188,7 @@ public abstract class PasswordFrame, S extends MPSite> exten // Password passwordField = Components.passwordField(); passwordField.setAlignmentX( Component.CENTER_ALIGNMENT ); - passwordField.setHorizontalAlignment( JTextField.CENTER ); + passwordField.setHorizontalAlignment( SwingConstants.CENTER ); passwordField.putClientProperty( "JPasswordField.cutCopyAllowed", true ); passwordField.setEditable( false ); passwordField.setBackground( null ); @@ -215,6 +217,7 @@ public abstract class PasswordFrame, S extends MPSite> exten setLocationRelativeTo( null ); } + @SuppressWarnings("MagicNumber") private void updateMask() { passwordField.setEchoChar( maskPasswordField.isSelected()? passwordEchoChar: (char) 0 ); passwordField.setFont( maskPasswordField.isSelected()? passwordEchoFont: Res.bigValueFont().deriveFont( 40f ) ); @@ -233,9 +236,9 @@ public abstract class PasswordFrame, S extends MPSite> exten return Futures.immediateCancelledFuture(); } - MPResultType resultType = resultTypeField.getModel().getElementAt( resultTypeField.getSelectedIndex() ); - MPMasterKey.Version siteVersion = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() ); - UnsignedInteger siteCounter = siteCounterModel.getNumber(); + MPResultType resultType = resultTypeField.getModel().getElementAt( resultTypeField.getSelectedIndex() ); + MPAlgorithm siteAlgorithm = siteVersionField.getItemAt( siteVersionField.getSelectedIndex() ).getAlgorithm(); + UnsignedInteger siteCounter = siteCounterModel.getNumber(); Iterable siteResults = user.findSites( siteNameQuery ); if (!allowNameCompletion) @@ -246,10 +249,10 @@ public abstract class PasswordFrame, S extends MPSite> exten } } ); 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() )) { site.setResultType( resultType ); - site.setAlgorithmVersion( siteVersion ); + site.setAlgorithm( siteAlgorithm ); site.setSiteCounter( siteCounter ); } @@ -259,7 +262,7 @@ public abstract class PasswordFrame, S extends MPSite> exten throws Exception { return user.getMasterKey() .siteResult( site.getSiteName(), site.getSiteCounter(), MPKeyPurpose.Authentication, null, site.getResultType(), - null, site.getAlgorithmVersion() ); + null, site.getAlgorithm() ); } } ); Futures.addCallback( passwordFuture, new FutureCallback() { @@ -276,7 +279,7 @@ public abstract class PasswordFrame, S extends MPSite> exten else siteActionButton.setText( "Add Site" ); resultTypeField.setSelectedItem( currentSite.getResultType() ); - siteVersionField.setSelectedItem( currentSite.getAlgorithmVersion() ); + siteVersionField.setSelectedItem( currentSite.getAlgorithm() ); siteCounterField.setValue( currentSite.getSiteCounter() ); siteNameField.setText( currentSite.getSiteName() ); if (siteNameField.getText().startsWith( siteNameQuery )) @@ -290,15 +293,14 @@ public abstract class PasswordFrame, S extends MPSite> exten } @Override - public void onFailure(final Throwable t) { + public void onFailure(@Nonnull final Throwable t) { } } ); return passwordFuture; } - protected abstract S createSite(U user, String siteName, UnsignedInteger siteCounter, MPResultType resultType, - MPMasterKey.Version algorithmVersion); + protected abstract S createSite(U user, String siteName, UnsignedInteger siteCounter, MPResultType resultType, MPAlgorithm algorithm); @Override public void insertUpdate(final DocumentEvent e) { diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/UnlockFrame.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/UnlockFrame.java index ae921515..0ed3fb85 100644 --- a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/UnlockFrame.java +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/UnlockFrame.java @@ -21,10 +21,10 @@ package com.lyndir.masterpassword.gui.view; import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*; 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.model.MPIncorrectMasterPasswordException; -import com.lyndir.masterpassword.model.MPUser; import java.awt.*; import java.awt.event.*; import java.util.concurrent.Future; @@ -196,7 +196,7 @@ public class UnlockFrame extends JFrame { } void trySignIn(final JComponent... signInComponents) { - if (!checkSignIn()) + if ((user == null) || !checkSignIn()) return; for (final JComponent signInComponent : signInComponents) diff --git a/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/package-info.java b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/package-info.java new file mode 100644 index 00000000..e41395e7 --- /dev/null +++ b/platform-independent/gui-java/src/main/java/com/lyndir/masterpassword/gui/view/package-info.java @@ -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 . +//============================================================================== + +/** + * @author lhunath, 2018-04-26 + */ +@ParametersAreNonnullByDefault +package com.lyndir.masterpassword.gui.view; + +import javax.annotation.ParametersAreNonnullByDefault;