Better scope preferences to the algorithm & clean up.
This commit is contained in:
parent
c115e9149c
commit
40a807c6af
@ -23,7 +23,7 @@ import com.google.common.primitives.UnsignedInteger;
|
|||||||
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||||
import com.lyndir.lhunath.opal.system.MessageDigests;
|
import com.lyndir.lhunath.opal.system.MessageDigests;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -33,6 +33,11 @@ import javax.annotation.Nullable;
|
|||||||
*/
|
*/
|
||||||
public interface MPAlgorithm {
|
public interface MPAlgorithm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: defaults: Password result type.
|
||||||
|
*/
|
||||||
|
MPResultType mpw_default_type = MPResultType.GeneratedLong;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpw: validity for the time-based rolling counter.
|
* mpw: validity for the time-based rolling counter.
|
||||||
*/
|
*/
|
||||||
@ -85,7 +90,7 @@ public interface MPAlgorithm {
|
|||||||
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
byte[] siteKey(byte[] masterKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
@Nullable String keyContext);
|
@Nullable String keyContext);
|
||||||
|
|
||||||
String siteResult(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
String siteResult(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
String sitePasswordFromTemplate(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
@ -94,6 +99,16 @@ public interface MPAlgorithm {
|
|||||||
|
|
||||||
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
|
||||||
|
|
||||||
String siteState(byte[] masterKey, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
String siteState(byte[] masterKey, byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
byte[] toBytes(int number);
|
||||||
|
|
||||||
|
byte[] toBytes(UnsignedInteger number);
|
||||||
|
|
||||||
|
byte[] toBytes(char[] characters);
|
||||||
|
|
||||||
|
byte[] toID(byte[] bytes);
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.base.*;
|
import com.google.common.base.*;
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
@ -54,7 +52,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
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 = bytesForInt( fullName.length() );
|
byte[] fullNameLengthBytes = toBytes( fullName.length() );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
logger.trc( "keyScope: %s", keyScope );
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
@ -63,26 +61,23 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
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( idForBytes( 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 = bytesForChars( 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 );
|
||||||
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
Arrays.fill( masterPasswordBytes, (byte) 0 );
|
||||||
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( toID( masterKey ) ) );
|
||||||
|
|
||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||||
try {
|
try {
|
||||||
//if (isAllowNative())
|
|
||||||
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 );
|
||||||
//else
|
|
||||||
// return SCrypt.scryptJ( 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 );
|
||||||
@ -102,10 +97,10 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
byte[] siteNameLengthBytes = toBytes( siteName.length() );
|
||||||
byte[] siteCounterBytes = bytesForInt( 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: bytesForInt( 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 );
|
||||||
@ -113,11 +108,11 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
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( idForBytes( sitePasswordInfo ) ) );
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( 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( idForBytes( sitePasswordSeedBytes ) ) );
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
return sitePasswordSeedBytes;
|
return sitePasswordSeedBytes;
|
||||||
}
|
}
|
||||||
@ -217,7 +212,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
throw logger.bug( "Could not derive result key." );
|
throw logger.bug( "Could not derive result key." );
|
||||||
|
|
||||||
// Base64-encode
|
// Base64-encode
|
||||||
String b64Key = Verify.verifyNotNull( CryptUtils.encodeBase64( resultKey ) );
|
String b64Key = Preconditions.checkNotNull( CryptUtils.encodeBase64( resultKey ) );
|
||||||
logger.trc( "b64 encoded -> key: %s", b64Key );
|
logger.trc( "b64 encoded -> key: %s", b64Key );
|
||||||
|
|
||||||
return b64Key;
|
return b64Key;
|
||||||
@ -236,7 +231,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
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
|
||||||
String cipherText = Verify.verifyNotNull( CryptUtils.encodeBase64( cipherBuf ) );
|
String cipherText = Preconditions.checkNotNull( CryptUtils.encodeBase64( cipherBuf ) );
|
||||||
logger.trc( "b64 encoded -> cipherText: %s", cipherText );
|
logger.trc( "b64 encoded -> cipherText: %s", cipherText );
|
||||||
|
|
||||||
return cipherText;
|
return cipherText;
|
||||||
@ -245,4 +240,32 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
throw logger.bug( e );
|
throw logger.bug( e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utilities
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes(final int number) {
|
||||||
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number ).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes(final UnsignedInteger number) {
|
||||||
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toBytes(final char[] characters) {
|
||||||
|
ByteBuffer byteBuffer = mpw_charset.encode( CharBuffer.wrap( characters ) );
|
||||||
|
|
||||||
|
byte[] bytes = new byte[byteBuffer.remaining()];
|
||||||
|
byteBuffer.get( bytes );
|
||||||
|
|
||||||
|
Arrays.fill( byteBuffer.array(), (byte) 0 );
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toID(final byte[] bytes) {
|
||||||
|
return mpw_hash.of( bytes );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.primitives.UnsignedBytes;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
@ -40,14 +41,14 @@ public class MPAlgorithmV1 extends MPAlgorithmV0 {
|
|||||||
|
|
||||||
// Determine the template.
|
// Determine the template.
|
||||||
Preconditions.checkState( siteKey.length > 0 );
|
Preconditions.checkState( siteKey.length > 0 );
|
||||||
int templateIndex = siteKey[0] & 0xFF; // Convert to unsigned int.
|
int templateIndex = UnsignedBytes.toInt( siteKey[0] );
|
||||||
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
MPTemplate template = resultType.getTemplateAtRollingIndex( templateIndex );
|
||||||
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
logger.trc( "template: %d => %s", templateIndex, template.getTemplateString() );
|
||||||
|
|
||||||
// Encode the password from the seed using the template.
|
// Encode the password from the seed using the template.
|
||||||
StringBuilder password = new StringBuilder( template.length() );
|
StringBuilder password = new StringBuilder( template.length() );
|
||||||
for (int i = 0; i < template.length(); ++i) {
|
for (int i = 0; i < template.length(); ++i) {
|
||||||
int characterIndex = siteKey[i + 1] & 0xFF; // Convert to unsigned int.
|
int characterIndex = UnsignedBytes.toInt( siteKey[i + 1] );
|
||||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||||
logger.trc( " - class: %c, index: %3d (0x%2H) => character: %c",
|
logger.trc( " - class: %c, index: %3d (0x%2H) => character: %c",
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
|
||||||
|
|
||||||
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.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
@ -48,26 +46,26 @@ public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
|||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter.longValue() == 0)
|
if (siteCounter.longValue() == 0)
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithm.mpw_otp_window * 1000)) * MPAlgorithm.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( MPAlgorithm.mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
byte[] siteNameLengthBytes = toBytes( siteNameBytes.length );
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
byte[] siteCounterBytes = toBytes( siteCounter );
|
||||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithm.mpw_charset );
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( mpw_charset );
|
||||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( 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( MPAlgorithm.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( idForBytes( sitePasswordInfo ) ) );
|
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( toID( sitePasswordInfo ) ) );
|
||||||
|
|
||||||
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
logger.trc( "siteKey: hmac-sha256( masterKey.id=%s, siteSalt )", CodeUtils.encodeHex( toID( masterKey ) ) );
|
||||||
byte[] sitePasswordSeedBytes = MPAlgorithm.mpw_digest.of( masterKey, sitePasswordInfo );
|
byte[] sitePasswordSeedBytes = mpw_digest.of( masterKey, sitePasswordInfo );
|
||||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( toID( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
return sitePasswordSeedBytes;
|
return sitePasswordSeedBytes;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.primitives.Bytes;
|
import com.google.common.primitives.Bytes;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -41,8 +39,8 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
byte[] fullNameBytes = fullName.getBytes( MPAlgorithm.mpw_charset );
|
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
||||||
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
byte[] fullNameLengthBytes = toBytes( fullNameBytes.length );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
logger.trc( "keyScope: %s", keyScope );
|
logger.trc( "keyScope: %s", keyScope );
|
||||||
@ -50,17 +48,17 @@ 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( MPAlgorithm.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( 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 )",
|
||||||
MPAlgorithm.scrypt_N, MPAlgorithm.scrypt_r, MPAlgorithm.scrypt_p );
|
scrypt_N, scrypt_r, scrypt_p );
|
||||||
byte[] mpBytes = bytesForChars( 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 );
|
||||||
Arrays.fill( mpBytes, (byte) 0 );
|
Arrays.fill( mpBytes, (byte) 0 );
|
||||||
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( idForBytes( masterKey ) ) );
|
logger.trc( " => masterKey.id: %s", CodeUtils.encodeHex( toID( masterKey ) ) );
|
||||||
|
|
||||||
return masterKey;
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.lyndir.lhunath.opal.system.CodeUtils;
|
import com.lyndir.lhunath.opal.system.CodeUtils;
|
||||||
@ -71,7 +69,8 @@ public class MPMasterKey {
|
|||||||
if (key == null) {
|
if (key == null) {
|
||||||
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_masterKey (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
logger.trc( "fullName: %s", fullName );
|
logger.trc( "fullName: %s", fullName );
|
||||||
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex( idForBytes( bytesForChars( masterPassword ) ) ) );
|
logger.trc( "masterPassword.id: %s", CodeUtils.encodeHex(
|
||||||
|
algorithmVersion.getAlgorithm().toID( algorithmVersion.getAlgorithm().toBytes( masterPassword ) ) ) );
|
||||||
|
|
||||||
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
|
keyByVersion.put( algorithmVersion, key = algorithmVersion.getAlgorithm().masterKey( fullName, masterPassword ) );
|
||||||
}
|
}
|
||||||
@ -175,7 +174,7 @@ public class MPMasterKey {
|
|||||||
public byte[] getKeyID(final Version algorithmVersion)
|
public byte[] getKeyID(final Version algorithmVersion)
|
||||||
throws MPInvalidatedException {
|
throws MPInvalidatedException {
|
||||||
|
|
||||||
return idForBytes( masterKey( algorithmVersion ) );
|
return algorithmVersion.getAlgorithm().toID( masterKey( algorithmVersion ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,8 +127,6 @@ public enum MPResultType {
|
|||||||
ImmutableList.<MPTemplate>of(), //
|
ImmutableList.<MPTemplate>of(), //
|
||||||
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
|
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
|
||||||
|
|
||||||
public static final MPResultType DEFAULT = GeneratedLong;
|
|
||||||
|
|
||||||
static final Logger logger = Logger.get( MPResultType.class );
|
static final Logger logger = Logger.get( MPResultType.class );
|
||||||
|
|
||||||
private final String shortName;
|
private final String shortName;
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
//==============================================================================
|
|
||||||
// This file is part of Master Password.
|
|
||||||
// Copyright (c) 2011-2017, Maarten Billemont.
|
|
||||||
//
|
|
||||||
// Master Password is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// Master Password is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You can find a copy of the GNU General Public License in the
|
|
||||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
|
||||||
//==============================================================================
|
|
||||||
|
|
||||||
package com.lyndir.masterpassword;
|
|
||||||
|
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author lhunath, 2017-09-20
|
|
||||||
*/
|
|
||||||
public final class MPUtils {
|
|
||||||
|
|
||||||
public static byte[] bytesForInt(final int number) {
|
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] bytesForInt(final UnsignedInteger number) {
|
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number.intValue() ).array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] bytesForChars(final char[] characters) {
|
|
||||||
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
|
|
||||||
|
|
||||||
byte[] bytes = new byte[byteBuffer.remaining()];
|
|
||||||
byteBuffer.get( bytes );
|
|
||||||
|
|
||||||
Arrays.fill( byteBuffer.array(), (byte) 0 );
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] idForBytes(final byte[] bytes) {
|
|
||||||
return MPAlgorithm.mpw_hash.of( bytes );
|
|
||||||
}
|
|
||||||
}
|
|
@ -48,7 +48,7 @@ public class MPFileSite extends MPSite {
|
|||||||
private Instant lastUsed;
|
private Instant lastUsed;
|
||||||
|
|
||||||
public MPFileSite(final MPFileUser user, final String siteName) {
|
public MPFileSite(final MPFileUser user, final String siteName) {
|
||||||
this( user, siteName, DEFAULT_COUNTER, MPResultType.DEFAULT, MPMasterKey.Version.CURRENT );
|
this( user, siteName, DEFAULT_COUNTER, user.getAlgorithmVersion().getAlgorithm().mpw_default_type, user.getAlgorithmVersion() );
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -51,7 +51,7 @@ public class MPFileUser extends MPUser<MPFileSite> implements Comparable<MPFileU
|
|||||||
}
|
}
|
||||||
|
|
||||||
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
|
public MPFileUser(final String fullName, @Nullable final byte[] keyID, final MPMasterKey.Version algorithmVersion) {
|
||||||
this( fullName, keyID, algorithmVersion, 0, MPResultType.DEFAULT, new Instant() );
|
this( fullName, keyID, algorithmVersion, 0, MPAlgorithm.mpw_default_type, new Instant() );
|
||||||
}
|
}
|
||||||
|
|
||||||
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 MPMasterKey.Version algorithmVersion, final int avatar,
|
||||||
|
@ -46,7 +46,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( MPMasterKey.Version.CURRENT.toInt() ).append( '\n' );
|
content.append( "# Algorithm: " ).append( user.getAlgorithmVersion().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" );
|
||||||
|
@ -59,7 +59,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 = MPResultType.DEFAULT;
|
MPResultType defaultType = MPAlgorithm.mpw_default_type;
|
||||||
|
|
||||||
//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 ))
|
||||||
|
@ -148,7 +148,7 @@ public final class Preferences {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public MPResultType getDefaultResultType() {
|
public MPResultType getDefaultResultType() {
|
||||||
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPResultType.DEFAULT.ordinal() )];
|
return MPResultType.values()[prefs().getInt( PREF_RESULT_TYPE, MPAlgorithm.mpw_default_type.ordinal() )];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
public boolean setDefaultVersion(final MPMasterKey.Version value) {
|
||||||
|
@ -26,7 +26,6 @@ import com.google.common.collect.FluentIterable;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
import com.google.common.util.concurrent.*;
|
import com.google.common.util.concurrent.*;
|
||||||
import com.lyndir.lhunath.opal.system.util.ObjectUtils;
|
|
||||||
import com.lyndir.masterpassword.*;
|
import com.lyndir.masterpassword.*;
|
||||||
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;
|
||||||
@ -146,7 +145,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
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( 12f ) );
|
||||||
resultTypeField.setSelectedItem( MPResultType.DEFAULT );
|
resultTypeField.setSelectedItem( MPAlgorithm.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) {
|
||||||
@ -156,7 +155,7 @@ public abstract class PasswordFrame<U extends MPUser<S>, S extends MPSite> exten
|
|||||||
|
|
||||||
siteVersionField.setFont( Res.valueFont().deriveFont( 12f ) );
|
siteVersionField.setFont( Res.valueFont().deriveFont( 12f ) );
|
||||||
siteVersionField.setAlignmentX( RIGHT_ALIGNMENT );
|
siteVersionField.setAlignmentX( RIGHT_ALIGNMENT );
|
||||||
siteVersionField.setSelectedItem( MPMasterKey.Version.CURRENT );
|
siteVersionField.setSelectedItem( user.getAlgorithmVersion() );
|
||||||
siteVersionField.addItemListener( new ItemListener() {
|
siteVersionField.addItemListener( new ItemListener() {
|
||||||
@Override
|
@Override
|
||||||
public void itemStateChanged(final ItemEvent e) {
|
public void itemStateChanged(final ItemEvent e) {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0545fc79995083ebebda07744ed9b22ee7ba6645
|
Subproject commit e886da7af01747972cde23ff09827b56dbba973c
|
Loading…
Reference in New Issue
Block a user