2
0

Initial native interface for scrypt.

This commit is contained in:
Maarten Billemont
2018-05-22 01:00:14 -04:00
parent faf59875bf
commit cc82e52c33
8 changed files with 366 additions and 26 deletions

View File

@@ -1,5 +1,6 @@
plugins {
id 'java'
id 'c'
}
description = 'Master Password Algorithm Implementation'
@@ -9,8 +10,69 @@ dependencies {
exclude( module: 'joda-time' )
}
compile 'com.github.joshjdevl.libsodiumjni:libsodium-jni:1.0.6'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.9.5'
compile group: 'org.jetbrains', name: 'annotations', version: '13.0'
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.1'
}
processResources {
dependsOn 'mpwSharedLibrary'
}
// TODO: nativeGenHeaders should run prior to mpwSharedLibrary
// TODO: but that creates a cyclic dependency since processResources runs before compileJava which nativeGenHeaders depends on.
//task mpwSharedLibrary {
// dependsOn processResources
//}
build {
// dependsOn 'mpwSharedLibrary'
dependsOn 'nativeGenHeaders'
}
task nativeGenHeaders {
description "Uses javah to regenerate the JNI header files"
inputs.file sourceSets.main.output.asFileTree.matching {
include 'com/lyndir/masterpassword/impl/MPAlgorithmV0.class'
}
outputs.file 'src/mpw/c/jni_mpw.h'
def classpath = files( sourceSets.main.compileClasspath, sourceSets.main.output )
doLast {
ant.javah( class: 'com.lyndir.masterpassword.impl.MPAlgorithmV0',
outputFile: 'src/mpw/c/jni_mpw.h',
classpath: classpath.asPath )
}
}
model {
components {
mpw( NativeLibrarySpec ) {
binaries.all {
if (targetPlatform.operatingSystem.macOsX) {
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/darwin"
cCompiler.args '-mmacosx-version-min=10.4'
linker.args '-mmacosx-version-min=10.4'
} else if (targetPlatform.operatingSystem.linux) {
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/linux"
cCompiler.args '-D_FILE_OFFSET_BITS=64'
} else if (targetPlatform.operatingSystem.windows) {
cCompiler.args "-I${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
cCompiler.args "-I${org.gradle.internal.jvm.Jvm.current().javaHome}/include/win32"
linker.args "Shlwapi.lib", "Advapi32.lib"
} else if (targetPlatform.operatingSystem.freeBSD) {
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include"
cCompiler.args '-I', "${org.gradle.internal.jvm.Jvm.current().javaHome}/include/freebsd"
}
}
// TODO: Can't we add the sharedLibraryFile to the resources through some kind of task dependency instead?
binaries.withType( SharedLibraryBinarySpec ) {
sourceSets.main.resources.srcDirs it.sharedLibraryFile.parent
// copy {
// from sharedLibraryFile
// to sourceSets.main.resources.outputDir
// }
}
}
}
}

View File

@@ -27,7 +27,6 @@ import com.google.common.primitives.Bytes;
import com.google.common.primitives.UnsignedInteger;
import com.lyndir.lhunath.opal.system.*;
import com.lyndir.lhunath.opal.system.logging.Logger;
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
import com.lyndir.masterpassword.*;
import java.nio.*;
import java.nio.charset.Charset;
@@ -38,7 +37,6 @@ import javax.annotation.Nullable;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.libsodium.jni.Sodium;
/**
@@ -53,8 +51,7 @@ public class MPAlgorithmV0 extends MPAlgorithm {
protected static final int AES_BLOCKSIZE = 128 /* bit */;
static {
if (Sodium.sodium_init() < 0)
throw new IllegalStateException( "Couldn't initialize libsodium." );
Native.load( MPAlgorithmV0.class, "mpw" );
}
public final Version version = MPAlgorithm.Version.V0;
@@ -93,7 +90,7 @@ public class MPAlgorithmV0 extends MPAlgorithm {
@Nullable
protected byte[] scrypt(final byte[] secret, final byte[] salt, final int keySize) {
byte[] buffer = new byte[keySize];
if (Sodium.crypto_pwhash_scryptsalsa208sha256_ll(
if (_scrypt(
secret, secret.length, salt, salt.length,
scrypt_N(), scrypt_r(), scrypt_p(), buffer, buffer.length ) < 0)
return null;
@@ -101,6 +98,8 @@ public class MPAlgorithmV0 extends MPAlgorithm {
return buffer;
}
protected native int _scrypt(byte[] passwd, int passwdlen, byte[] salt, int saltlen, int N, int r, int p, byte[] buf, int buflen);
@Override
public byte[] siteKey(final byte[] masterKey, final String siteName, UnsignedInteger siteCounter,
final MPKeyPurpose keyPurpose, @Nullable final String keyContext) {
@@ -259,27 +258,29 @@ public class MPAlgorithmV0 extends MPAlgorithm {
public String siteResultFromDerive(final byte[] masterKey, final byte[] siteKey,
final MPResultType resultType, @Nullable final String resultParam) {
if (resultType == MPResultType.DeriveKey) {
int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
if (resultParamInt == 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 );
throw new UnsupportedOperationException( "TODO" );
// Derive key
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." );
// Base64-encode
String b64Key = Preconditions.checkNotNull( BaseEncoding.base64().encode( resultKey ) );
logger.trc( "b64 encoded -> key: %s", b64Key );
return b64Key;
} else
throw logger.bug( "Unsupported derived password type: %s", resultType );
// if (resultType == MPResultType.DeriveKey) {
// int resultParamInt = ConversionUtils.toIntegerNN( resultParam );
// if (resultParamInt == 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 );
// if (resultKey == null)
// throw logger.bug( "Could not derive result key." );
//
// // Base64-encode
// String b64Key = Preconditions.checkNotNull( BaseEncoding.base64().encode( resultKey ) );
// logger.trc( "b64 encoded -> key: %s", b64Key );
//
// return b64Key;
// } else
// throw logger.bug( "Unsupported derived password type: %s", resultType );
}
@Override

View File

@@ -0,0 +1,59 @@
//==============================================================================
// 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.impl;
import com.google.common.io.ByteStreams;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.io.*;
/**
* @author lhunath, 2018-05-22
*/
public final class Native {
private static final Logger logger = Logger.get( Native.class );
private static final char FILE_DOT = '.';
private static final String NATIVES_PATH = "";
@SuppressWarnings({ "HardcodedFileSeparator", "LoadLibraryWithNonConstantString" })
public static void load(final Class<?> context, final String name) {
try {
String library = System.mapLibraryName( name );
int libraryDot = library.lastIndexOf( FILE_DOT );
String libraryName = (libraryDot > 0)? library.substring( 0, libraryDot ): library;
String libraryExtension = (libraryDot > 0)? library.substring( libraryDot ): "lib";
String libraryResource = String.format( "%s/%s", NATIVES_PATH, library );
InputStream libraryStream = context.getResourceAsStream( libraryResource );
if (libraryStream == null)
throw new IllegalStateException(
"Library: " + name + " (" + libraryResource + "), not found in class loader for: " + context );
File libraryFile = File.createTempFile( "libmpw", ".dylib" );
ByteStreams.copy( libraryStream, new FileOutputStream( libraryFile ) );
System.load( libraryFile.getAbsolutePath() );
libraryFile.deleteOnExit();
if (!libraryFile.delete())
logger.wrn( "Couldn't clean up library after loading: " + libraryFile );
}
catch (final IOException e) {
throw new IllegalStateException( "Couldn't load library: " + name, e );
}
}
}

View File

@@ -0,0 +1,8 @@
#include "jni_mpw.h"
/** native int _scrypt(byte[] passwd, int passwdlen, byte[] salt, int saltlen, int N, int r, int p, byte[] buf, int buflen); */
JNIEXPORT jint JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1scrypt(JNIEnv *env, jobject obj,
jbyteArray passwd, jint passwdlen, jbyteArray salt, jint saltlen, jint N, jint r, jint p, jbyteArray buf, jint buflen) {
return -2;
}

View File

@@ -0,0 +1,23 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lyndir_masterpassword_impl_MPAlgorithmV0 */
#ifndef _Included_com_lyndir_masterpassword_impl_MPAlgorithmV0
#define _Included_com_lyndir_masterpassword_impl_MPAlgorithmV0
#ifdef __cplusplus
extern "C" {
#endif
#undef com_lyndir_masterpassword_impl_MPAlgorithmV0_AES_BLOCKSIZE
#define com_lyndir_masterpassword_impl_MPAlgorithmV0_AES_BLOCKSIZE 128L
/*
* Class: com_lyndir_masterpassword_impl_MPAlgorithmV0
* Method: _scrypt
* Signature: ([BI[BIIII[BI)I
*/
JNIEXPORT jint JNICALL Java_com_lyndir_masterpassword_impl_MPAlgorithmV0__1scrypt
(JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint, jint, jint, jint, jbyteArray, jint);
#ifdef __cplusplus
}
#endif
#endif