2
0

Clean up aes state, default to 512 key size, improve log output.

This commit is contained in:
Maarten Billemont 2017-09-24 12:00:38 -04:00
parent 39dcef46d2
commit b4c2a393f1
11 changed files with 125 additions and 91 deletions

View File

@ -1,6 +1,8 @@
language: objective-c
os: osx
osx_image: xcode8.3
env: TERM=dumb SHLVL=0
cache: false
git:
submodules: true
script:

View File

@ -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.
Cipher();
bzero( RoundKey, keyExpSize );
}
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();
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;
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)
@ -592,6 +598,8 @@ void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, co
state = (state_t*)output;
InvCipher();
}
bzero( RoundKey, keyExpSize );
}
#endif // #if defined(AES_CBC) && (AES_CBC == 1)

View File

@ -175,7 +175,7 @@ const char *mpw_siteState(
trc( "-- mpw_siteState (algorithm: %u)\n", algorithmVersion );
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)
return NULL;

View File

@ -180,7 +180,7 @@ static const char *mpw_sitePasswordFromCrypt_v0(
mpw_free( &plainBytes, bufSize );
if (!plainText)
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;
}
@ -195,6 +195,8 @@ static const char *mpw_sitePasswordFromDerive_v0(
return NULL;
}
int resultParamInt = atoi( resultParam );
if (!resultParamInt)
resultParamInt = 512;
if (resultParamInt < 128 || resultParamInt > 512 || resultParamInt % 8 != 0) {
err( "Parameter is not a valid key size (should be 128 - 512): %s\n", resultParam );
return NULL;

View File

@ -44,6 +44,24 @@ time_t mpw_mktime(
&tm.tm_hour, &tm.tm_min, &tm.tm_sec ) == 6) {
tm.tm_year -= 1900; // tm_year 0 = rfc3339 year 1900
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 );
}

View File

@ -18,15 +18,65 @@
package com.lyndir.masterpassword;
import com.google.common.base.Charsets;
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.nio.ByteOrder;
import java.nio.charset.Charset;
import javax.annotation.Nullable;
/**
* @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();
@ -45,5 +95,5 @@ public interface MPAlgorithm extends Serializable {
String sitePasswordFromDerive(byte[] masterKey, byte[] siteKey, MPResultType resultType, @Nullable String resultParam);
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);
}

View File

@ -29,7 +29,6 @@ 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.*;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.annotation.Nullable;
@ -38,49 +37,11 @@ import javax.crypto.IllegalBlockSizeException;
/**
* @see MPMasterKey.Version#V0
*
* @author lhunath, 2014-08-30
* @see MPMasterKey.Version#V0
*/
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() );
@Override
@ -118,10 +79,10 @@ public class MPAlgorithmV0 implements MPAlgorithm {
protected byte[] scrypt(final byte[] masterKeySalt, final byte[] mpBytes) {
try {
// if (isAllowNative())
//if (isAllowNative())
return SCrypt.scrypt( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
// else
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
//else
// return SCrypt.scryptJ( mpBytes, masterKeySalt, scrypt_N, scrypt_r, scrypt_p, mpw_dkLen );
}
catch (final GeneralSecurityException e) {
throw logger.bug( e );
@ -179,7 +140,8 @@ public class MPAlgorithmV0 implements MPAlgorithm {
}
@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];
for (int i = 0; i < siteKey.length; ++i) {
@ -213,7 +175,8 @@ public class MPAlgorithmV0 implements MPAlgorithm {
}
@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.checkArgument( !resultParam.isEmpty() );
@ -226,7 +189,7 @@ public class MPAlgorithmV0 implements MPAlgorithm {
// Decrypt
byte[] plainBuf = CryptUtils.decrypt( cipherBuf, masterKey, true );
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;
}
@ -236,13 +199,13 @@ public class MPAlgorithmV0 implements MPAlgorithm {
}
@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) {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
if (resultParamInt == 0)
resultParamInt = 512;
if ((resultParamInt < 128) || (resultParamInt > 512) || ((resultParamInt % 8) != 0))
throw logger.bug( "Parameter is not a valid key size (should be 128 - 512): %s", resultParam );
int keySize = resultParamInt / 8;
@ -258,19 +221,14 @@ public class MPAlgorithmV0 implements MPAlgorithm {
logger.trc( "b64 encoded -> key: %s", b64Key );
return b64Key;
}
else
} else
throw logger.bug( "Unsupported derived password type: %s", resultType );
}
@Override
public String siteState(final byte[] masterKey, final byte[] siteKey, final String siteName, final UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose,
@Nullable final String keyContext, final MPResultType resultType, @Nullable final String resultParam) {
Preconditions.checkNotNull( resultParam );
Preconditions.checkArgument( !resultParam.isEmpty() );
@Nullable final String keyContext, final MPResultType resultType, final String resultParam) {
try {
// Encrypt

View File

@ -20,7 +20,6 @@ package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.CodeUtils;
@ -49,25 +48,25 @@ public class MPAlgorithmV2 extends MPAlgorithmV1 {
// OTP counter value.
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.
byte[] siteNameBytes = siteName.getBytes( MPAlgorithmV0.mpw_charset );
byte[] siteNameBytes = siteName.getBytes( MPAlgorithm.mpw_charset );
byte[] siteNameLengthBytes = bytesForInt( siteNameBytes.length );
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 );
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( MPAlgorithmV0.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
byte[] sitePasswordInfo = Bytes.concat( keyScope.getBytes( MPAlgorithm.mpw_charset ), siteNameLengthBytes, siteNameBytes, siteCounterBytes );
if (keyContextBytes != null)
sitePasswordInfo = Bytes.concat( sitePasswordInfo, keyContextLengthBytes, keyContextBytes );
logger.trc( " => siteSalt.id: %s", CodeUtils.encodeHex( idForBytes( sitePasswordInfo ) ) );
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 ) ) );
return sitePasswordSeedBytes;

View File

@ -20,11 +20,8 @@ package com.lyndir.masterpassword;
import static com.lyndir.masterpassword.MPUtils.*;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import com.lyndir.lhunath.opal.system.CodeUtils;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Arrays;
@ -44,7 +41,7 @@ public class MPAlgorithmV3 extends MPAlgorithmV2 {
@Override
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 );
String keyScope = MPKeyPurpose.Authentication.getScope();
@ -53,12 +50,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( 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 ) ) );
// Calculate the master key.
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[] masterKey = scrypt( masterKeySalt, mpBytes );
Arrays.fill( masterKeySalt, (byte) 0 );

View File

@ -155,7 +155,7 @@ public class MPMasterKey {
logger.trc( "-- mpw_siteState (algorithm: %d)", algorithmVersion.toInt() );
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(
masterKey, siteKey, siteName, siteCounter, keyPurpose, keyContext, resultType, resultParam );

View File

@ -30,15 +30,15 @@ import java.util.Arrays;
public final class MPUtils {
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) {
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) {
ByteBuffer byteBuffer = MPAlgorithmV0.mpw_charset.encode( CharBuffer.wrap( characters ) );
ByteBuffer byteBuffer = MPAlgorithm.mpw_charset.encode( CharBuffer.wrap( characters ) );
byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get( bytes );
@ -48,6 +48,6 @@ public final class MPUtils {
}
public static byte[] idForBytes(final byte[] bytes) {
return MPAlgorithmV0.mpw_hash.of( bytes );
return MPAlgorithm.mpw_hash.of( bytes );
}
}