Skip to content
This repository was archived by the owner on May 25, 2021. It is now read-only.

Add Windows Native Library #27

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ Building Native Implementation
JAVA_HOME - base directory of a Java 6+ JDK
NDK_ROOT - base directory of Android NDK

A precompiled native library for Android 2.3 running on ARM is located in
src/android/resources/lib/arm5/libscrypt.so. If placed in an .apk file's
lib/armeabi directory it will be automatically loaded.
A set of precompiled native libraries for Android 2.3 for several
architecture is located in src/android/resources/lib/. If placed in
an .apk file's lib/ directory the proper native library will be
automatically loaded.

Extra Notes on Android Native Implementation

To build your own android native libraries with NDK, read the
instructions in src/android/README.md
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jarsigner-plugin</artifactId>
<version>1.2</version>
<version>1.3.2</version>
<executions>
<execution>
<id>sign</id>
Expand Down
2 changes: 2 additions & 0 deletions src/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
obj/
libs/
56 changes: 56 additions & 0 deletions src/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
To build and use native library on android, do the following:

### Build

1. download and install Android NDK [1]

1. check (and potentially edit) the target platform defined in
src/android/jni/Android.mk as TARGET_PLATFORM [2]

1. check (and potentially edit) the target architectures defined in
src/android/jni/Application.mk as APP_ABI [3]

1. make sure your current directory is src/android/jni

1. run `ndk-build`

1. if you want to clean the build, run `ndk-build clean`

1. the result native libraries for the platforms/architectures you
chose would be resulted in src/android/libs

### Useage

1. since the android build tool chain will reject to include a jar
file with native library that no android platform supports and the
official scrypt build include such libraries, you need to strip
those libraries (and potentially the signature) from the scrypt jar
you are going to use in the android project.

1. in the android project (following eclipse adt directory structure
conventions) you want to use scrypt with native libraries, make
sure there's a folder called libs under the project root.

1. copy the striped scrypt jar file to the libs folder of your android
project.

1. copy the subfolders of src/android/libs you just built to the libs
folder of your android project.

1. build and package your android application and it should be using
one of the native scrypt libraries matching the device's
architecture.

Hint: you can always make sure you're calling the native version of
scrypt instead of the java version by specifically use
`com.lambdaworks.crypto.SCrypt.scryptN(..)`
instead of
`com.lambdaworks.crypto.SCrypt.scrypt(..)`

[1]: https://developer.android.com/tools/sdk/ndk/index.html
[2]: https://developer.android.com/ndk/guides/android_mk.html
[3]: https://developer.android.com/ndk/guides/application_mk.html

- - -

Haochen Xie
16 changes: 16 additions & 0 deletions src/android/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
LOCAL_PATH := $(call my-dir)

SSE2 :=
TARGET_PLATFORM := android-9

include $(CLEAR_VARS)
LOCAL_MODULE := scrypt

LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/c/*.c)
LOCAL_SRC_FILES := $(filter-out $(if $(SSE2),%-nosse.c,%-sse.c),$(LOCAL_SRC_FILES))
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include

LOCAL_CFLAGS += -DANDROID -DHAVE_CONFIG_H -DANDROID_TARGET_ARCH="$(TARGET_ARCH)"
LOCAL_LDFLAGS += -lc -llog

include $(BUILD_SHARED_LIBRARY)
1 change: 1 addition & 0 deletions src/android/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
APP_ABI := armeabi armeabi-v7a x86 x86_64 mips
1 change: 1 addition & 0 deletions src/android/jni/c
1 change: 1 addition & 0 deletions src/android/jni/include
Binary file removed src/android/resources/lib/arm5/libscrypt.so
Binary file not shown.
Binary file not shown.
Binary file added src/android/resources/lib/armeabi/libscrypt.so
Binary file not shown.
Binary file added src/android/resources/lib/mips/libscrypt.so
Binary file not shown.
Binary file added src/android/resources/lib/x86/libscrypt.so
Binary file not shown.
Binary file added src/android/resources/lib/x86_64/libscrypt.so
Binary file not shown.
54 changes: 54 additions & 0 deletions src/main/c/scrypt_jni.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,31 @@
#include <jni.h>
#include "crypto_scrypt.h"

#ifdef ANDROID

#include <android/log.h>
#include <stdint.h>

#define ANDROID_LOG_TAG "ScryptLog"
#define ALOG(msg, ...) __android_log_print(ANDROID_LOG_VERBOSE, ANDROID_LOG_TAG, msg, ##__VA_ARGS__)

#define STR1(x) #x
#define STR(x) STR1(x)

void log_basic_info();
void log_params(JNIEnv *env, jbyteArray passwd, jbyteArray salt, jint N, jint r, jint p, jint dkLen);

#endif

jbyteArray JNICALL scryptN(JNIEnv *env, jclass cls, jbyteArray passwd, jbyteArray salt,
jint N, jint r, jint p, jint dkLen)
{

#ifdef ANDROID
log_basic_info();
log_params(env, passwd, salt, N, r, p, dkLen);
#endif

jint Plen = (*env)->GetArrayLength(env, passwd);
jint Slen = (*env)->GetArrayLength(env, salt);
jbyte *P = (*env)->GetByteArrayElements(env, passwd, NULL);
Expand Down Expand Up @@ -51,6 +73,38 @@ jbyteArray JNICALL scryptN(JNIEnv *env, jclass cls, jbyteArray passwd, jbyteArra
return DK;
}

#ifdef ANDROID

char *get_byte_array_summary(JNIEnv *env, jbyteArray jarray) {
int len = (*env)->GetArrayLength(env, jarray);
jbyte *bytes = (*env)->GetByteArrayElements(env, jarray, NULL);

static char buff[10240];
int i;
for (i = 0; i < len; ++i) {
buff[i] = bytes[i] % 32 + 'a';
}
buff[i] = '\0';

if (bytes) (*env)->ReleaseByteArrayElements(env, jarray, bytes, JNI_ABORT);

return buff;
}

void log_params(JNIEnv *env, jbyteArray passwd, jbyteArray salt, jint N, jint r, jint p, jint dkLen) {
ALOG("Parameters for native scrypt run:");
ALOG("passwd (summary): %s", get_byte_array_summary(env, passwd));
ALOG("salt (summary): %s", get_byte_array_summary(env, salt));
ALOG("N, r, p, dkLen: %d, %d, %d, %d", (int32_t) N, (int32_t) r, (int32_t) p, (int32_t) dkLen);
}

void log_basic_info() {
ALOG("Basic info for native scrypt run:");
ALOG("Native library targeting arch: %s", STR(ANDROID_TARGET_ARCH));
}

#endif

static const JNINativeMethod methods[] = {
{ "scryptN", "([B[BIIII)[B", (void *) scryptN }
};
Expand Down
15 changes: 11 additions & 4 deletions src/main/java/com/lambdaworks/jni/JarLibraryLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ public boolean load(String name, boolean verify) {

try {
Platform platform = Platform.detect();
JarFile jar = new JarFile(codeSource.getLocation().getPath(), verify);
JarFile jar = new JarFile(new File(codeSource.getLocation().toURI()), verify);
try {
for (String path : libCandidates(platform, name)) {
JarEntry entry = jar.getJarEntry(path);
if (entry == null) continue;

File lib = extract(name, jar.getInputStream(entry));
String ext = path.contains(".")
? path.substring(path.lastIndexOf("."))
: "lib";

File lib = extract(name, ext, jar.getInputStream(entry));
System.load(lib.getAbsolutePath());
lib.delete();

Expand All @@ -89,11 +93,11 @@ public boolean load(String name, boolean verify) {
*
* @throws IOException when an IO error occurs.
*/
private static File extract(String name, InputStream is) throws IOException {
private static File extract(String name, String ext, InputStream is) throws IOException {
byte[] buf = new byte[4096];
int len;

File lib = File.createTempFile(name, "lib");
File lib = File.createTempFile(name, ext);
FileOutputStream os = new FileOutputStream(lib);

try {
Expand Down Expand Up @@ -138,6 +142,9 @@ private List<String> libCandidates(Platform platform, String name) {
case freebsd:
candidates.add(sb + ".so");
break;
case windows:
candidates.add(sb + ".dll");
break;
}

return candidates;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/lambdaworks/jni/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum Arch {
public enum OS {
darwin ("darwin|mac os x"),
freebsd("freebsd"),
linux ("linux");
linux ("linux"),
windows ("windows .*");

Pattern pattern;

Expand Down
Binary file added src/main/resources/lib/x86/windows/libscrypt.dll
Binary file not shown.
Binary file not shown.
45 changes: 45 additions & 0 deletions src/test/js/scryptSpeed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Example command for running this testing utility:
*
* <pre>
* jjs -cp ~/.m2/repository/commons-codec/commons-codec/1.10/commons-codec-1.10.jar:target/scrypt-1.4.0.jar scryptTimer.js
* </pre>
*
* If you don't have commons-codec, use the following command to download with Maven:
*
* <pre>
* mvn dependency:get -Dartifact=commons-codec:commons-codec:1.10
* </pre>
*
*/

var SCrypt = com.lambdaworks.crypto.SCrypt;
var System = java.lang.System;
var Hex = org.apache.commons.codec.binary.Hex;

var f = Hex.class.getClassLoader().loadClass("com.lambdaworks.crypto.SCrypt").getDeclaredField("native_library_loaded");
f.setAccessible(true);
var native = f.get(null);
System.out.println("Using " + (native ? "Native" : "Java") + " scrypt implementation." );

var startTs = System.currentTimeMillis();

var P, S, N, r, p, dkLen;
var expected, actual;

P = "pleaseletmein".getBytes("UTF-8");
S = "SodiumChloride".getBytes("UTF-8");
N = 1048576;
r = 8;
p = 1;
dkLen = 64;
expected = "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4";

actual = SCrypt.scrypt(P, S, N, r, p, dkLen);
actual = Hex.encodeHexString(actual);

var endTs = System.currentTimeMillis();

System.out.println("expect: " + expected);
System.out.println("actual: " + actual);
System.out.println("Time: " + (endTs - startTs) / 1000 + " sec");
26 changes: 26 additions & 0 deletions src/windows/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Windows Native Library for Java Implementation of Scrypt
========================================================

This directory (/src/windows) contains files needed to build a Windows
dynamic library to be loaded by JNI mechanism employed by the [Java
implementation of Scrypt](https://github.com/wg/scrypt).

Most of the codes are taken from
[https://github.com/barrysteyn/scrypt-windows], so all credits should
go to Barry Steyn.

To build the dynamic loading library for Windows, JDK (1.7 or higher)
and Microsoft Windows SDK (tested with SDK 7.1) should be installed,
and JAVA_HOME should be set to the installed JDK, the Windows SDK's
Bin/ directory should be in PATH (we are calling setenv.bat from the
build script.) After you have the environment setup, simply double
click on the build.bat should do the trick. After a successful
building, you will get libscrypt32.dll and libscrypt64.dll in your
(project root)/target directory.

The scrypt-windows project contains 3 implementations of scrypt. In
this project, I picked the one with SSE optimization. If you want to
use the others, go to
[https://github.com/barrysteyn/scrypt-windows/tree/master/scrypt-1.1.6/lib/crypto]
and pick one from crypto_scrypt-{ref,nosse,sse}.c to replace
c/crypto_scrypt-sse.c.
18 changes: 18 additions & 0 deletions src/windows/build.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
set local enableextensions

@echo Building libscrypt.dll for x86
call setenv /Release /x86
mkdir ..\..\target\native\win32
cl /O2 /EHs /MD /Iinclude /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" /c /Fo..\..\target\native\win32\ /DHAVE_CONFIG_H c\*.c
link /DLL /nologo /MACHINE:x86 /OUT:..\..\target\native\win32\libscrypt.dll ..\..\target\native\win32\*.obj
copy /Y ..\..\target\native\win32\libscrypt.dll ..\..\target\libscrypt32.dll

@echo Building libscrypt.dll for x64
call setenv /Release /x64
mkdir ..\..\target\native\win64
cl /O2 /EHs /MD /Iinclude /I"%JAVA_HOME%\include" /I"%JAVA_HOME%\include\win32" /c /Fo..\..\target\native\win64\ /DHAVE_CONFIG_H c\*.c
link /DLL /nologo /MACHINE:x64 /OUT:..\..\target\native\win64\libscrypt.dll ..\..\target\native\win64\*.obj
copy /Y ..\..\target\native\win64\libscrypt.dll ..\..\target\libscrypt64.dll

endlocal

Expand Down
Loading