From cc82e52c338df8e95b4322b14c31ec7498ab635a Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Tue, 22 May 2018 01:00:14 -0400 Subject: [PATCH] Initial native interface for scrypt. --- core/java/algorithm/build.gradle | 64 ++++++- .../masterpassword/impl/MPAlgorithmV0.java | 51 ++--- .../lyndir/masterpassword/impl/Native.java | 59 ++++++ core/java/algorithm/src/mpw/c/jni_mpw.c | 8 + core/java/algorithm/src/mpw/c/jni_mpw.h | 23 +++ core/java/tests/build.gradle | 3 + .../project.pbxproj | 181 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + 8 files changed, 366 insertions(+), 26 deletions(-) create mode 100644 core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/Native.java create mode 100644 core/java/algorithm/src/mpw/c/jni_mpw.c create mode 100644 core/java/algorithm/src/mpw/c/jni_mpw.h create mode 100644 platform-darwin/MasterPassword-JNI/MasterPassword-JNI.xcodeproj/project.pbxproj diff --git a/core/java/algorithm/build.gradle b/core/java/algorithm/build.gradle index 857d711b..7d2a00fa 100644 --- a/core/java/algorithm/build.gradle +++ b/core/java/algorithm/build.gradle @@ -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 +// } + } + } + } +} diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java index 2bbac74b..75cf15e4 100644 --- a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/MPAlgorithmV0.java @@ -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 diff --git a/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/Native.java b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/Native.java new file mode 100644 index 00000000..9852ea48 --- /dev/null +++ b/core/java/algorithm/src/main/java/com/lyndir/masterpassword/impl/Native.java @@ -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 . +//============================================================================== + +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 ); + } + } +} diff --git a/core/java/algorithm/src/mpw/c/jni_mpw.c b/core/java/algorithm/src/mpw/c/jni_mpw.c new file mode 100644 index 00000000..c4532d7c --- /dev/null +++ b/core/java/algorithm/src/mpw/c/jni_mpw.c @@ -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; +} diff --git a/core/java/algorithm/src/mpw/c/jni_mpw.h b/core/java/algorithm/src/mpw/c/jni_mpw.h new file mode 100644 index 00000000..990e3440 --- /dev/null +++ b/core/java/algorithm/src/mpw/c/jni_mpw.h @@ -0,0 +1,23 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* 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 diff --git a/core/java/tests/build.gradle b/core/java/tests/build.gradle index b4033b02..56242948 100644 --- a/core/java/tests/build.gradle +++ b/core/java/tests/build.gradle @@ -11,4 +11,7 @@ dependencies { testCompile group: 'org.testng', name: 'testng', version: '6.8.5' testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2' } +//tasks.withType(Test) { +// systemProperty "java.library.path", "/Users/lhunath/Documents/workspace/lyndir/MasterPassword/core/java/algorithm/build/libs/mpw/shared" +//} test.useTestNG() diff --git a/platform-darwin/MasterPassword-JNI/MasterPassword-JNI.xcodeproj/project.pbxproj b/platform-darwin/MasterPassword-JNI/MasterPassword-JNI.xcodeproj/project.pbxproj new file mode 100644 index 00000000..9ade388c --- /dev/null +++ b/platform-darwin/MasterPassword-JNI/MasterPassword-JNI.xcodeproj/project.pbxproj @@ -0,0 +1,181 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXFileReference section */ + DA1554DE20B3928E00EA92C5 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = ""; }; + DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-algorithm.h"; sourceTree = ""; }; + DA1554E020B3928E00EA92C5 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = ""; }; + DA1554E120B3928E00EA92C5 /* mpw-marshal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal.c"; sourceTree = ""; }; + DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v2.c"; sourceTree = ""; }; + DA1554E320B3928E00EA92C5 /* mpw-types.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-types.c"; sourceTree = ""; }; + DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-marshal-util.c"; sourceTree = ""; }; + DA1554E520B3928E00EA92C5 /* mpw-util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-util.c"; sourceTree = ""; }; + DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v1.c"; sourceTree = ""; }; + DA1554E720B3928E00EA92C5 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = ""; }; + DA1554E820B3928E00EA92C5 /* mpw-marshal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal.h"; sourceTree = ""; }; + DA1554E920B3928E00EA92C5 /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = ""; }; + DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm.c"; sourceTree = ""; }; + DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v0.c"; sourceTree = ""; }; + DA1554EC20B3928E00EA92C5 /* mpw-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-types.h"; sourceTree = ""; }; + DA1554ED20B3928E00EA92C5 /* mpw-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-util.h"; sourceTree = ""; }; + DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mpw-marshal-util.h"; sourceTree = ""; }; + DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "mpw-algorithm_v3.c"; sourceTree = ""; }; + DA1554F120B392A100EA92C5 /* jni_mpw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jni_mpw.h; sourceTree = ""; }; + DA1554F220B392A100EA92C5 /* jni_mpw.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jni_mpw.c; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + DA1554D220B3924000EA92C5 = { + isa = PBXGroup; + children = ( + DA1554F020B392A100EA92C5 /* jni */, + DA1554DD20B3928E00EA92C5 /* core */, + ); + sourceTree = ""; + }; + DA1554DD20B3928E00EA92C5 /* core */ = { + isa = PBXGroup; + children = ( + DA1554DE20B3928E00EA92C5 /* aes.c */, + DA1554DF20B3928E00EA92C5 /* mpw-algorithm.h */, + DA1554E020B3928E00EA92C5 /* base64.h */, + DA1554E120B3928E00EA92C5 /* mpw-marshal.c */, + DA1554E220B3928E00EA92C5 /* mpw-algorithm_v2.c */, + DA1554E320B3928E00EA92C5 /* mpw-types.c */, + DA1554E420B3928E00EA92C5 /* mpw-marshal-util.c */, + DA1554E520B3928E00EA92C5 /* mpw-util.c */, + DA1554E620B3928E00EA92C5 /* mpw-algorithm_v1.c */, + DA1554E720B3928E00EA92C5 /* aes.h */, + DA1554E820B3928E00EA92C5 /* mpw-marshal.h */, + DA1554E920B3928E00EA92C5 /* base64.c */, + DA1554EA20B3928E00EA92C5 /* mpw-algorithm.c */, + DA1554EB20B3928E00EA92C5 /* mpw-algorithm_v0.c */, + DA1554EC20B3928E00EA92C5 /* mpw-types.h */, + DA1554ED20B3928E00EA92C5 /* mpw-util.h */, + DA1554EE20B3928E00EA92C5 /* mpw-marshal-util.h */, + DA1554EF20B3928E00EA92C5 /* mpw-algorithm_v3.c */, + ); + name = core; + path = ../../core/c; + sourceTree = ""; + }; + DA1554F020B392A100EA92C5 /* jni */ = { + isa = PBXGroup; + children = ( + DA1554F120B392A100EA92C5 /* jni_mpw.h */, + DA1554F220B392A100EA92C5 /* jni_mpw.c */, + ); + name = jni; + path = ../../core/java/algorithm/src/mpw/c; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXLegacyTarget section */ + DA1554D720B3924000EA92C5 /* MasterPassword-JNI */ = { + isa = PBXLegacyTarget; + buildArgumentsString = ":masterpassword-algorithm:nativeGenHeaders"; + buildConfigurationList = DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */; + buildPhases = ( + ); + buildToolPath = gradle; + buildWorkingDirectory = /Users/lhunath/Documents/workspace/lyndir/MasterPassword/gradle; + dependencies = ( + ); + name = "MasterPassword-JNI"; + passBuildSettingsInEnvironment = 1; + productName = "MasterPassword-JNI"; + }; +/* End PBXLegacyTarget section */ + +/* Begin PBXProject section */ + DA1554D320B3924000EA92C5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "Maarten Billemont"; + TargetAttributes = { + DA1554D720B3924000EA92C5 = { + CreatedOnToolsVersion = 9.3.1; + }; + }; + }; + buildConfigurationList = DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = DA1554D220B3924000EA92C5; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DA1554D720B3924000EA92C5 /* MasterPassword-JNI */, + ); + }; +/* End PBXProject section */ + +/* Begin XCBuildConfiguration section */ + DA1554D820B3924000EA92C5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home/include/**", + ); + }; + name = Debug; + }; + DA1554D920B3924000EA92C5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "/Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home/include/**", + ); + }; + name = Release; + }; + DA1554DB20B3924000EA92C5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home; + }; + name = Debug; + }; + DA1554DC20B3924000EA92C5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + JAVA_HOME = /Library/Java/JavaVirtualMachines/jdk1.8.0_161.jdk/Contents/Home; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + DA1554D620B3924000EA92C5 /* Build configuration list for PBXProject "MasterPassword-JNI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA1554D820B3924000EA92C5 /* Debug */, + DA1554D920B3924000EA92C5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DA1554DA20B3924000EA92C5 /* Build configuration list for PBXLegacyTarget "MasterPassword-JNI" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA1554DB20B3924000EA92C5 /* Debug */, + DA1554DC20B3924000EA92C5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = DA1554D320B3924000EA92C5 /* Project object */; +} diff --git a/platform-darwin/MasterPassword.xcworkspace/contents.xcworkspacedata b/platform-darwin/MasterPassword.xcworkspace/contents.xcworkspacedata index 4cd05f9b..d31ca6db 100644 --- a/platform-darwin/MasterPassword.xcworkspace/contents.xcworkspacedata +++ b/platform-darwin/MasterPassword.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,9 @@ + +