Clean up aes state, default to 512 key size, improve log output.
This commit is contained in:
parent
39dcef46d2
commit
b4c2a393f1
@ -1,6 +1,8 @@
|
|||||||
language: objective-c
|
language: objective-c
|
||||||
|
os: osx
|
||||||
osx_image: xcode8.3
|
osx_image: xcode8.3
|
||||||
env: TERM=dumb SHLVL=0
|
env: TERM=dumb SHLVL=0
|
||||||
|
cache: false
|
||||||
git:
|
git:
|
||||||
submodules: true
|
submodules: true
|
||||||
script:
|
script:
|
||||||
|
@ -486,6 +486,8 @@ void AES_ECB_encrypt(uint8_t *output, const uint8_t *input, const uint32_t lengt
|
|||||||
|
|
||||||
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||||
Cipher();
|
Cipher();
|
||||||
|
|
||||||
|
bzero( RoundKey, keyExpSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
|
void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t length, const uint8_t *key)
|
||||||
@ -499,6 +501,8 @@ void AES_ECB_decrypt(uint8_t *output, const uint8_t *input, const uint32_t lengt
|
|||||||
KeyExpansion();
|
KeyExpansion();
|
||||||
|
|
||||||
InvCipher();
|
InvCipher();
|
||||||
|
|
||||||
|
bzero( RoundKey, keyExpSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -555,6 +559,8 @@ void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, co
|
|||||||
state = (state_t*)output;
|
state = (state_t*)output;
|
||||||
Cipher();
|
Cipher();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bzero( RoundKey, keyExpSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
|
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)
|
||||||
@ -592,6 +598,8 @@ void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, co
|
|||||||
state = (state_t*)output;
|
state = (state_t*)output;
|
||||||
InvCipher();
|
InvCipher();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bzero( RoundKey, keyExpSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // #if defined(AES_CBC) && (AES_CBC == 1)
|
#endif // #if defined(AES_CBC) && (AES_CBC == 1)
|
||||||
|
@ -175,7 +175,7 @@ const char *mpw_siteState(
|
|||||||
|
|
||||||
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
|
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
|
||||||
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
trc( "resultType: %d (%s)\n", resultType, mpw_nameForType( resultType ) );
|
||||||
trc( "resultParam: %s\n", resultParam );
|
trc( "resultParam: %zu bytes = %s\n", sizeof( resultParam ), resultParam );
|
||||||
if (!masterKey || !resultParam)
|
if (!masterKey || !resultParam)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ static const char *mpw_sitePasswordFromCrypt_v0(
|
|||||||
mpw_free( &plainBytes, bufSize );
|
mpw_free( &plainBytes, bufSize );
|
||||||
if (!plainText)
|
if (!plainText)
|
||||||
err( "AES decryption error: %s\n", strerror( errno ) );
|
err( "AES decryption error: %s\n", strerror( errno ) );
|
||||||
trc( "decrypted -> plainText: %s\n", plainText );
|
trc( "decrypted -> plainText: %zu bytes = %s = %s\n", sizeof( plainText ), plainText, mpw_hex( plainText, sizeof( plainText ) ) );
|
||||||
|
|
||||||
return plainText;
|
return plainText;
|
||||||
}
|
}
|
||||||
@ -195,6 +195,8 @@ static const char *mpw_sitePasswordFromDerive_v0(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int resultParamInt = atoi( resultParam );
|
int resultParamInt = atoi( resultParam );
|
||||||
|
if (!resultParamInt)
|
||||||
|
resultParamInt = 512;
|
||||||
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
|
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
|
||||||
err( "Parameter is not a valid key size (should be 128 - 512): %s\n", resultParam );
|
err( "Parameter is not a valid key size (should be 128 - 512): %s\n", resultParam );
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -44,6 +44,24 @@ time_t mpw_mktime(
|
|||||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
|
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
|
||||||
tm.tm_year -= 1900; // tm_year 0 = rfc3339 year 1900
|
tm.tm_year -= 1900; // tm_year 0 = rfc3339 year 1900
|
||||||
tm.tm_mon -= 1; // tm_mon 0 = rfc3339 month 1
|
tm.tm_mon -= 1; // tm_mon 0 = rfc3339 month 1
|
||||||
|
/*
|
||||||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
|
||||||
|
frame #0: 0x00007fff9fe4d219 libsystem_notify.dylib`_nc_table_find_64 + 22
|
||||||
|
libsystem_notify.dylib`_nc_table_find_64:
|
||||||
|
-> 0x7fff9fe4d219 <+22>: divl 0x4(%rdi)
|
||||||
|
0x7fff9fe4d21c <+25>: movq 0x8(%rdi), %rax
|
||||||
|
0x7fff9fe4d220 <+29>: movq (%rax,%rdx,8), %rcx
|
||||||
|
0x7fff9fe4d224 <+33>: xorl %eax, %eax
|
||||||
|
(lldb) bt
|
||||||
|
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)
|
||||||
|
* frame #0: 0x00007fff9fe4d219 libsystem_notify.dylib`_nc_table_find_64 + 22
|
||||||
|
frame #1: 0x00007fff9fe4a21e libsystem_notify.dylib`registration_node_find + 53
|
||||||
|
frame #2: 0x00007fff9fe4b78d libsystem_notify.dylib`notify_check + 105
|
||||||
|
frame #3: 0x00007fff9fccc164 libsystem_c.dylib`notify_check_tz + 24
|
||||||
|
frame #4: 0x00007fff9fccbd97 libsystem_c.dylib`tzsetwall_basic + 45
|
||||||
|
frame #5: 0x00007fff9fccdcd0 libsystem_c.dylib`mktime + 46
|
||||||
|
frame #6: 0x0000000100009496 mpw`mpw_mktime(time="2017-04-16T03:16:35Z") at mpw-marshal-util.c:47
|
||||||
|
*/
|
||||||
return mktime( &tm );
|
return mktime( &tm );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,15 +18,65 @@
|
|||||||
|
|
||||||
package com.lyndir.masterpassword;
|
package com.lyndir.masterpassword;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.primitives.UnsignedInteger;
|
import com.google.common.primitives.UnsignedInteger;
|
||||||
|
import com.lyndir.lhunath.opal.system.MessageAuthenticationDigests;
|
||||||
|
import com.lyndir.lhunath.opal.system.MessageDigests;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see MPMasterKey.Version
|
* @see MPMasterKey.Version
|
||||||
*/
|
*/
|
||||||
public interface MPAlgorithm extends Serializable {
|
public interface MPAlgorithm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: validity for the time-based rolling counter.
|
||||||
|
*/
|
||||||
|
int mpw_otp_window = 5 * 60 /* s */;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Key ID hash.
|
||||||
|
*/
|
||||||
|
MessageDigests mpw_hash = MessageDigests.SHA256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Site digest.
|
||||||
|
*/
|
||||||
|
MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Platform-agnostic byte order.
|
||||||
|
*/
|
||||||
|
ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Input character encoding.
|
||||||
|
*/
|
||||||
|
Charset mpw_charset = Charsets.UTF_8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpw: Master key size (byte).
|
||||||
|
*/
|
||||||
|
int mpw_dkLen = 64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Parallelization parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_p = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: Memory cost parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_r = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scrypt: CPU cost parameter.
|
||||||
|
*/
|
||||||
|
int scrypt_N = 32768;
|
||||||
|
|
||||||
MPMasterKey.Version getAlgorithmVersion();
|
MPMasterKey.Version getAlgorithmVersion();
|
||||||
|
|
||||||
@ -45,5 +95,5 @@ public interface MPAlgorithm extends Serializable {
|
|||||||
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, final byte[] siteKey, String siteName, UnsignedInteger siteCounter, MPKeyPurpose keyPurpose,
|
||||||
@Nullable String keyContext, MPResultType resultType, @Nullable String resultParam);
|
@Nullable String keyContext, MPResultType resultType, String resultParam);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ import com.lyndir.lhunath.opal.system.*;
|
|||||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||||
import java.nio.*;
|
import java.nio.*;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -38,49 +37,11 @@ import javax.crypto.IllegalBlockSizeException;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see MPMasterKey.Version#V0
|
|
||||||
*
|
|
||||||
* @author lhunath, 2014-08-30
|
* @author lhunath, 2014-08-30
|
||||||
|
* @see MPMasterKey.Version#V0
|
||||||
*/
|
*/
|
||||||
public class MPAlgorithmV0 implements MPAlgorithm {
|
public class MPAlgorithmV0 implements MPAlgorithm {
|
||||||
|
|
||||||
/**
|
|
||||||
* mpw: validity for the time-based rolling counter.
|
|
||||||
*/
|
|
||||||
protected static final int mpw_otp_window = 5 * 60 /* s */;
|
|
||||||
/**
|
|
||||||
* mpw: Key ID hash.
|
|
||||||
*/
|
|
||||||
protected static final MessageDigests mpw_hash = MessageDigests.SHA256;
|
|
||||||
/**
|
|
||||||
* mpw: Site digest.
|
|
||||||
*/
|
|
||||||
protected static final MessageAuthenticationDigests mpw_digest = MessageAuthenticationDigests.HmacSHA256;
|
|
||||||
/**
|
|
||||||
* mpw: Platform-agnostic byte order.
|
|
||||||
*/
|
|
||||||
protected static final ByteOrder mpw_byteOrder = ByteOrder.BIG_ENDIAN;
|
|
||||||
/**
|
|
||||||
* mpw: Input character encoding.
|
|
||||||
*/
|
|
||||||
protected static final Charset mpw_charset = Charsets.UTF_8;
|
|
||||||
/**
|
|
||||||
* mpw: Master key size (byte).
|
|
||||||
*/
|
|
||||||
protected static final int mpw_dkLen = 64;
|
|
||||||
/**
|
|
||||||
* scrypt: Parallelization parameter.
|
|
||||||
*/
|
|
||||||
protected static final int scrypt_p = 2;
|
|
||||||
/**
|
|
||||||
* scrypt: Memory cost parameter.
|
|
||||||
*/
|
|
||||||
protected static final int scrypt_r = 8;
|
|
||||||
/**
|
|
||||||
* scrypt: CPU cost parameter.
|
|
||||||
*/
|
|
||||||
protected static final int scrypt_N = 32768;
|
|
||||||
|
|
||||||
protected final Logger logger = Logger.get( getClass() );
|
protected final Logger logger = Logger.get( getClass() );
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -92,7 +53,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
public byte[] masterKey(final String fullName, final char[] masterPassword) {
|
||||||
|
|
||||||
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
byte[] fullNameBytes = fullName.getBytes( mpw_charset );
|
||||||
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
byte[] fullNameLengthBytes = bytesForInt( fullName.length() );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
@ -100,7 +61,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
||||||
|
|
||||||
@ -108,7 +69,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
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 = bytesForChars( 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( idForBytes( masterKey ) ) );
|
||||||
@ -118,10 +79,10 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
|
||||||
try {
|
try {
|
||||||
// if (isAllowNative())
|
//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
|
//else
|
||||||
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
|
// 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 );
|
||||||
@ -140,10 +101,10 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (mpw_otp_window * 1000)) * mpw_otp_window );
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( mpw_charset );
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
byte[] siteNameLengthBytes = bytesForInt( siteName.length() );
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
byte[] siteCounterBytes = bytesForInt( 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: bytesForInt( 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 ),
|
||||||
@ -179,7 +140,8 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
public String sitePasswordFromTemplate(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
int[] _siteKey = new int[siteKey.length];
|
int[] _siteKey = new int[siteKey.length];
|
||||||
for (int i = 0; i < siteKey.length; ++i) {
|
for (int i = 0; i < siteKey.length; ++i) {
|
||||||
@ -192,16 +154,16 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
|
|
||||||
// Determine the template.
|
// Determine the template.
|
||||||
Preconditions.checkState( _siteKey.length > 0 );
|
Preconditions.checkState( _siteKey.length > 0 );
|
||||||
int templateIndex = _siteKey[0];
|
int templateIndex = _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];
|
int characterIndex = _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: %5d (0x%2H) => character: %c",
|
logger.trc( " - class: %c, index: %5d (0x%2H) => character: %c",
|
||||||
characterClass.getIdentifier(), characterIndex, _siteKey[i + 1], passwordCharacter );
|
characterClass.getIdentifier(), characterIndex, _siteKey[i + 1], passwordCharacter );
|
||||||
|
|
||||||
@ -213,7 +175,8 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
public String sitePasswordFromCrypt(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
Preconditions.checkNotNull( resultParam );
|
Preconditions.checkNotNull( resultParam );
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
Preconditions.checkArgument( !resultParam.isEmpty() );
|
||||||
@ -226,7 +189,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
// Decrypt
|
// Decrypt
|
||||||
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
|
||||||
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
String plainText = mpw_charset.decode( ByteBuffer.wrap( plainBuf ) ).toString();
|
||||||
logger.trc( "decrypted -> plainText: %s", plainText );
|
logger.trc( "decrypted -> plainText: %d bytes = %s = %s", plainBuf.length, plainText, CodeUtils.encodeHex( plainBuf ) );
|
||||||
|
|
||||||
return plainText;
|
return plainText;
|
||||||
}
|
}
|
||||||
@ -236,13 +199,13 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType, @Nullable final String resultParam) {
|
public String sitePasswordFromDerive(final byte[] masterKey, final byte[] siteKey, final MPResultType resultType,
|
||||||
|
@Nullable final String resultParam) {
|
||||||
|
|
||||||
if (resultType == MPResultType.DeriveKey) {
|
if (resultType == MPResultType.DeriveKey) {
|
||||||
Preconditions.checkNotNull( resultParam );
|
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
|
||||||
|
|
||||||
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
|
||||||
|
if (resultParamInt == 0)
|
||||||
|
resultParamInt = 512;
|
||||||
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
|
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
|
||||||
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
|
||||||
int keySize = resultParamInt / 8;
|
int keySize = resultParamInt / 8;
|
||||||
@ -258,19 +221,14 @@ public class MPAlgorithmV0 implements MPAlgorithm {
|
|||||||
logger.trc( "b64 encoded -> key: %s", b64Key );
|
logger.trc( "b64 encoded -> key: %s", b64Key );
|
||||||
|
|
||||||
return b64Key;
|
return b64Key;
|
||||||
}
|
} else
|
||||||
|
|
||||||
else
|
|
||||||
throw logger.bug( "Unsupported derived password type: %s", resultType );
|
throw logger.bug( "Unsupported derived password type: %s", resultType );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
|
||||||
final MPKeyPurpose keyPurpose,
|
final MPKeyPurpose keyPurpose,
|
||||||
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
|
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
|
||||||
|
|
||||||
Preconditions.checkNotNull( resultParam );
|
|
||||||
Preconditions.checkArgument( !resultParam.isEmpty() );
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Encrypt
|
// Encrypt
|
||||||
|
@ -20,7 +20,6 @@ package com.lyndir.masterpassword;
|
|||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
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;
|
||||||
@ -49,25 +48,25 @@ public class MPAlgorithmV2 extends MPAlgorithmV1 {
|
|||||||
|
|
||||||
// OTP counter value.
|
// OTP counter value.
|
||||||
if (siteCounter.longValue() == 0)
|
if (siteCounter.longValue() == 0)
|
||||||
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithmV0.mpw_otp_window * 1000)) * MPAlgorithmV0.mpw_otp_window );
|
siteCounter = UnsignedInteger.valueOf( (System.currentTimeMillis() / (MPAlgorithm.mpw_otp_window * 1000)) * MPAlgorithm.mpw_otp_window );
|
||||||
|
|
||||||
// Calculate the site seed.
|
// Calculate the site seed.
|
||||||
byte[] siteNameBytes = siteName.getBytes( MPAlgorithmV0.mpw_charset );
|
byte[] siteNameBytes = siteName.getBytes( MPAlgorithm.mpw_charset );
|
||||||
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
|
||||||
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
byte[] siteCounterBytes = bytesForInt( siteCounter );
|
||||||
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithmV0.mpw_charset );
|
byte[] keyContextBytes = ((keyContext == null) || keyContext.isEmpty())? null: keyContext.getBytes( MPAlgorithm.mpw_charset );
|
||||||
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( keyContextBytes.length );
|
byte[] keyContextLengthBytes = (keyContextBytes == null)? null: bytesForInt( 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( MPAlgorithmV0.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
|
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MPAlgorithm.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( idForBytes( 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( idForBytes( masterKey ) ) );
|
||||||
byte[] sitePasswordSeedBytes = MPAlgorithmV0.mpw_digest.of( masterKey, sitePasswordInfo );
|
byte[] sitePasswordSeedBytes = MPAlgorithm.mpw_digest.of( masterKey, sitePasswordInfo );
|
||||||
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
logger.trc( " => siteKey.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordSeedBytes ) ) );
|
||||||
|
|
||||||
return sitePasswordSeedBytes;
|
return sitePasswordSeedBytes;
|
||||||
|
@ -20,11 +20,8 @@ package com.lyndir.masterpassword;
|
|||||||
|
|
||||||
import static com.lyndir.masterpassword.MPUtils.*;
|
import static com.lyndir.masterpassword.MPUtils.*;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
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.nio.ByteBuffer;
|
|
||||||
import java.nio.CharBuffer;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
@ -44,7 +41,7 @@ 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( MPAlgorithmV0.mpw_charset );
|
byte[] fullNameBytes = fullName.getBytes( MPAlgorithm.mpw_charset );
|
||||||
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
byte[] fullNameLengthBytes = MPUtils.bytesForInt( fullNameBytes.length );
|
||||||
|
|
||||||
String keyScope = MPKeyPurpose.Authentication.getScope();
|
String keyScope = MPKeyPurpose.Authentication.getScope();
|
||||||
@ -53,12 +50,12 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
|
|||||||
// Calculate the master key salt.
|
// Calculate the master key salt.
|
||||||
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
logger.trc( "masterKeySalt: keyScope=%s | #fullName=%s | fullName=%s",
|
||||||
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
keyScope, CodeUtils.encodeHex( fullNameLengthBytes ), fullName );
|
||||||
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MPAlgorithmV0.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
byte[] masterKeySalt = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), fullNameLengthBytes, fullNameBytes );
|
||||||
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( masterKeySalt ) ) );
|
logger.trc( " => masterKeySalt.id: %s", CodeUtils.encodeHex( idForBytes( 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 )",
|
||||||
MPAlgorithmV0.scrypt_N, MPAlgorithmV0.scrypt_r, MPAlgorithmV0.scrypt_p );
|
MPAlgorithm.scrypt_N, MPAlgorithm.scrypt_r, MPAlgorithm.scrypt_p );
|
||||||
byte[] mpBytes = bytesForChars( masterPassword );
|
byte[] mpBytes = bytesForChars( masterPassword );
|
||||||
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
byte[] masterKey = scrypt( masterKeySalt, mpBytes );
|
||||||
Arrays.fill( masterKeySalt, (byte) 0 );
|
Arrays.fill( masterKeySalt, (byte) 0 );
|
||||||
|
@ -155,7 +155,7 @@ public class MPMasterKey {
|
|||||||
|
|
||||||
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
|
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
|
||||||
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
logger.trc( "resultType: %d (%s)", resultType.getType(), resultType.getShortName() );
|
||||||
logger.trc( "resultParam: %s", resultParam );
|
logger.trc( "resultParam: %d bytes = %s", resultParam.getBytes( MPAlgorithm.mpw_charset ).length, resultParam );
|
||||||
|
|
||||||
return algorithmVersion.getAlgorithm().siteState(
|
return algorithmVersion.getAlgorithm().siteState(
|
||||||
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );
|
||||||
|
@ -30,15 +30,15 @@ import java.util.Arrays;
|
|||||||
public final class MPUtils {
|
public final class MPUtils {
|
||||||
|
|
||||||
public static byte[] bytesForInt(final int number) {
|
public static byte[] bytesForInt(final int number) {
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithmV0.mpw_byteOrder ).putInt( number ).array();
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number ).array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] bytesForInt(final UnsignedInteger number) {
|
public static byte[] bytesForInt(final UnsignedInteger number) {
|
||||||
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithmV0.mpw_byteOrder ).putInt( number.intValue() ).array();
|
return ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MPAlgorithm.mpw_byteOrder ).putInt( number.intValue() ).array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] bytesForChars(final char[] characters) {
|
public static byte[] bytesForChars(final char[] characters) {
|
||||||
ByteBuffer byteBuffer = MPAlgorithmV0.mpw_charset.encode( CharBuffer.wrap( characters ) );
|
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
|
||||||
|
|
||||||
byte[] bytes = new byte[byteBuffer.remaining()];
|
byte[] bytes = new byte[byteBuffer.remaining()];
|
||||||
byteBuffer.get( bytes );
|
byteBuffer.get( bytes );
|
||||||
@ -48,6 +48,6 @@ public final class MPUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] idForBytes(final byte[] bytes) {
|
public static byte[] idForBytes(final byte[] bytes) {
|
||||||
return MPAlgorithmV0.mpw_hash.of( bytes );
|
return MPAlgorithm.mpw_hash.of( bytes );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user