From a8bbfc2ecb94f67fdd61e54c317404e5115d0ab1 Mon Sep 17 00:00:00 2001 From: minebreaker Date: Fri, 15 Feb 2019 22:38:12 +0900 Subject: [PATCH 01/23] Gradle --- .gitignore | 3 + README.md | 11 ++ build.gradle | 51 ++++++ gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 ++++++++++++++++++ gradlew.bat | 84 +++++++++ pom.xml | 116 ------------ settings.gradle | 2 + .../argon2/Argon2ArgumentFactory.java | 162 ----------------- .../java/at/gadermaier/argon2/Benchmark.java | 88 --------- src/main/java/at/gadermaier/argon2/Main.java | 30 --- src/test/java/Argon2Test.java | 2 +- src/test/java/BaseTest.java | 15 -- src/test/java/InitializeTest.java | 19 +- src/test/java/MainSuite.java | 11 -- 15 files changed, 345 insertions(+), 426 deletions(-) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat delete mode 100644 pom.xml create mode 100644 settings.gradle delete mode 100644 src/main/java/at/gadermaier/argon2/Argon2ArgumentFactory.java delete mode 100644 src/main/java/at/gadermaier/argon2/Benchmark.java delete mode 100644 src/main/java/at/gadermaier/argon2/Main.java delete mode 100644 src/test/java/BaseTest.java delete mode 100644 src/test/java/MainSuite.java diff --git a/.gitignore b/.gitignore index 051ea92..0cf15c3 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,6 @@ aws.properties .vagrant/ Vagrantfile + +.gradle/ +build/ diff --git a/README.md b/README.md index e10955c..4e5651f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +Fork of [https://github.com/andreas1327250/argon2-java]() + +* Refactored to be used as a library +* Removed commons-cli + +License: MIT + + +================ ↓↓↓ Original Documentation ↓↓↓ ================ + + # Argon2 Java implementation This is a pure Java implementation of [Argon2](https://github.com/P-H-C/phc-winner-argon2). It targets Java 6. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7da8646 --- /dev/null +++ b/build.gradle @@ -0,0 +1,51 @@ +plugins { + id 'java' +} + +group 'rip.deadcode.argon2' +version '0.1-SNAPSHOT' + +repositories { + mavenCentral() + maven { + url = "https://dl.bintray.com/minebreaker/test" + } +} + +dependencies { +// compile( +// 'com.google.guava:guava:27.0.1-jre', +// 'com.google.code.findbugs:jsr305:3.0.2', +// 'com.google.code.gson:gson:2.8.5', +// 'com.google.mug:mug:1.12', +// 'com.typesafe:config:1.3.3', +// 'org.slf4j:slf4j-api:1.7.25', +// 'org.slf4j:jul-to-slf4j:1.7.25', // Guava uses java.util.logging +// 'ch.qos.logback:logback-classic:1.2.3' +// ) +// compileOnly 'org.projectlombok:lombok:1.16.20' + testCompile( + 'org.junit.jupiter:junit-jupiter-api:5.3.2', + 'com.google.truth:truth:0.42', + 'com.google.truth.extensions:truth-java8-extension:0.42', + 'org.mockito:mockito-core:2.23.4', + 'rip.deadcode:izvestia:0.2', +// 'com.google.jimfs:jimfs:1.1' + ) + testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.3.2' +} + +test { + useJUnitPlatform() +} + +sourceCompatibility = 1.6 +targetCompatibility = 1.6 + +compileJava { + options.encoding = 'UTF-8' +} + +compileTestJava { + options.encoding = 'UTF-8' +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..1b2b07c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 01ed6b1..0000000 --- a/pom.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - 4.0.0 - - at.gadermaier - argon2 - 0.1 - - - - commons-cli - commons-cli - 1.3 - compile - - - - junit - junit - ${junit.version} - test - - - - org.hamcrest - hamcrest-all - ${hamcrest.version} - test - - - - - - - - maven-compiler-plugin - 3.0 - - 1.6 - 1.6 - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - at.gadermaier.argon2.Main - - - - - jar-with-dependencies - - false - jar-with-dependencies - - - - make-assembly - package - - single - - - - - - - - - - maven-surefire-plugin - 2.19.1 - - alphabetical - - - - - - - - - UTF-8 - 4.12 - 1.3 - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..1f08d54 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'argon2' + diff --git a/src/main/java/at/gadermaier/argon2/Argon2ArgumentFactory.java b/src/main/java/at/gadermaier/argon2/Argon2ArgumentFactory.java deleted file mode 100644 index 8cc9a7f..0000000 --- a/src/main/java/at/gadermaier/argon2/Argon2ArgumentFactory.java +++ /dev/null @@ -1,162 +0,0 @@ -package at.gadermaier.argon2; - -import at.gadermaier.argon2.model.Argon2Type; -import org.apache.commons.cli.*; - -import static java.lang.Integer.parseInt; - -public class Argon2ArgumentFactory { - - static Argon2 parseArguments(String[] args){ - - Options options = buildOptions(); - - CommandLineParser parser = new DefaultParser(); - HelpFormatter formatter = new HelpFormatter(); - CommandLine commandLine = null; - - try { - commandLine = parser.parse(options, args); - - if(commandLine.getArgs().length != 1) - throw new ParseException("no password or salt"); - - return createArgon2(commandLine); - } catch (ParseException e) { - formatter.printHelp("argon2 salt", options,true); - System.out.println("Password is read from stdin"); - - bailOut(); - } - - // not reachable - return null; - } - - private static Argon2 createArgon2(CommandLine commandLine) throws ParseException { - Argon2 argon2 = new Argon2(); - String salt = commandLine.getArgs()[0]; - - argon2.setSalt(salt); - - if(commandLine.hasOption("h")) - throw new ParseException("usage"); - - if(commandLine.hasOption("t")){ - argon2.setIterations(parseInt(commandLine.getOptionValue("t"))); - } - - if(commandLine.hasOption("p")){ - argon2.setParallelism(parseInt(commandLine.getOptionValue("p"))); - } - - if(commandLine.hasOption("m")){ - argon2.setMemory(parseInt(commandLine.getOptionValue("m"))); - }else if(commandLine.hasOption("k")){ - int k = parseInt(commandLine.getOptionValue("k")); - if(k % 4*argon2.getLanes() != 0) - throw new ParseException("k must be a multiple of p*4"); - argon2.setMemoryInKiB(k); - } - - - if(commandLine.hasOption("e")){ - argon2.setEncodedOnly(true); - }else if(commandLine.hasOption("r")){ - argon2.setRawOnly(true); - } - - if(commandLine.hasOption("i")){ - argon2.setType(Argon2Type.Argon2i); - }else if(commandLine.hasOption("d")){ - argon2.setType(Argon2Type.Argon2d); - }else if(commandLine.hasOption("id")){ - argon2.setType(Argon2Type.Argon2id); - } - - if (commandLine.hasOption(("l"))) { - argon2.setOutputLength(parseInt(commandLine.getOptionValue("l"))); - } - - if(commandLine.hasOption("v")){ - int version = parseInt(commandLine.getOptionValue("v")); - if (!(version == 10 || version == 13)) { - bailOut("wrong version"); - } - argon2.setVersion(version); - } - - return argon2; - } - - private static Options buildOptions(){ - Options options = new Options(); - Option option; - - OptionGroup optionGroup = new OptionGroup(); - - option = new Option("i", null, false, "Use Argon2i (this is the default)"); - optionGroup.addOption(option); - option = new Option("d", null, false, "Use Argon2d instead of Argon2i"); - optionGroup.addOption(option); - option = new Option("id", null, false, "Use Argon2id instead of Argon2i"); - optionGroup.addOption(option); - - options.addOptionGroup(optionGroup); - - - option = new Option("t", null, true, "Sets the number of iterations to N (default = 3)"); - option.setArgName("N"); - option.setType(Integer.class); - options.addOption(option); - - optionGroup = new OptionGroup(); - - option = new Option("m", null, true, "Sets the memory usage of 2^N KiB (default 12)"); - option.setArgName("N"); - option.setType(Integer.class); - optionGroup.addOption(option); - - option = new Option("k", null, true, "Sets the memory usage of N KiB (default 2^12)"); - option.setArgName("N"); - option.setType(Integer.class); - optionGroup.addOption(option); - - options.addOptionGroup(optionGroup); - - - option = new Option("p", null, true, "Sets parallelism to N (default 1)"); - option.setArgName("N"); - option.setType(Integer.class); - options.addOption(option); - - option = new Option("l", null, true, "Sets hash output length to N bytes (default 32)"); - option.setArgName("N"); - option.setType(Integer.class); - options.addOption(option); - - - optionGroup = new OptionGroup(); - - option = new Option("e", null, false, "Output only encoded hash"); - optionGroup.addOption(option); - option = new Option("r", null, false, "Output only the raw bytes of the hash"); - optionGroup.addOption(option); - - options.addOptionGroup(optionGroup); - - option = new Option("h", null, false, "Print usage"); - options.addOption(option); - - return options; - } - - private static void bailOut(String message){ - System.out.println(message); - bailOut(); - } - - private static void bailOut(){ - System.exit(1); - } -} diff --git a/src/main/java/at/gadermaier/argon2/Benchmark.java b/src/main/java/at/gadermaier/argon2/Benchmark.java deleted file mode 100644 index 429e44f..0000000 --- a/src/main/java/at/gadermaier/argon2/Benchmark.java +++ /dev/null @@ -1,88 +0,0 @@ -package at.gadermaier.argon2; - -import at.gadermaier.argon2.model.Argon2Type; - -import static at.gadermaier.argon2.Constants.Defaults.ARGON2_VERSION_NUMBER; -import static at.gadermaier.argon2.model.Argon2Type.Argon2d; -import static at.gadermaier.argon2.model.Argon2Type.Argon2i; - -public class Benchmark { - - public static void main(String[] args) { - if (args.length > 0) - benchmark(Integer.parseInt(args[0])); - else - benchmark(18); - } - - /* - * Benchmarks Argon2 with salt length 16, password length 16, t_cost 1, - * and different m_cost and threads - */ - private static void benchmark(int maxMemory) { - - System.out.println("threads;memory;seconds"); - - int inlen = 16; - int outlen = 16; - - int t_cost = 3; - int m_cost; - int[] thread_test = new int[]{1, 2, 4, 8}; - Argon2Type[] types = new Argon2Type[]{Argon2i, Argon2d}; - - byte[] pwdBytes = new byte[inlen]; - byte[] saltBytes = new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; - - //warmup jit - Argon2Factory.create() - .setIterations(10) - .setParallelism(4) - .hash("password".toCharArray(), "saltsalt"); - - for (m_cost = 10; m_cost <= maxMemory; m_cost++) { - for (int i = 0; i < 4; i++) { - - - double run_time = 0; - int thread_n = thread_test[i]; - - int runs = 3; - run(outlen, t_cost, m_cost, types, pwdBytes, saltBytes, run_time, thread_n, runs); - System.gc(); - } - } - } - - private static void run(int outlen, int t_cost, int m_cost, Argon2Type[] types, byte[] pwdBytes, byte[] saltBytes, double run_time, int thread_n, int runs) { - for(int averageIndex=0; averageIndex Date: Sat, 16 Feb 2019 15:44:56 +0900 Subject: [PATCH 02/23] Removed Factory --- README.md | 2 +- src/main/java/at/gadermaier/argon2/Argon2.java | 11 ++++++++--- .../java/at/gadermaier/argon2/Argon2Factory.java | 7 ------- .../at/gadermaier/argon2/algorithm/FillMemory.java | 12 ++++-------- src/test/java/Argon2Test.java | 4 ++-- src/test/java/InitializeTest.java | 7 ++----- 6 files changed, 17 insertions(+), 26 deletions(-) delete mode 100644 src/main/java/at/gadermaier/argon2/Argon2Factory.java diff --git a/README.md b/README.md index 4e5651f..6b71855 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Fork of [https://github.com/andreas1327250/argon2-java]() * Refactored to be used as a library * Removed commons-cli -License: MIT +License: MIT (Same as original) ================ ↓↓↓ Original Documentation ↓↓↓ ================ diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index 7c0bbc8..79a0b90 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -10,9 +10,12 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static at.gadermaier.argon2.Constants.Defaults.*; + public class Argon2 { private byte[] output; @@ -37,7 +40,9 @@ public class Argon2 { private boolean encodedOnly = false; private boolean rawOnly = false; - Argon2() { + private ExecutorService executor = Executors.newCachedThreadPool(); + + public Argon2() { this.lanes = LANES_DEF; this.outputLength = OUTLEN_DEF; this.memory = 1 << LOG_M_COST_DEF; @@ -75,7 +80,7 @@ public String hash() { try { argon2_hash(); return getOutputString(); - }finally { + } finally { clear(); } } @@ -88,7 +93,7 @@ private void argon2_hash() { Instance instance = new Instance(this); Initialize.initialize(instance, this); - FillMemory.fillMemoryBlocks(instance); + FillMemory.fillMemoryBlocks(instance, executor); Finalize.finalize(instance, this); duration = (System.nanoTime() - start) / 1000000000.0; diff --git a/src/main/java/at/gadermaier/argon2/Argon2Factory.java b/src/main/java/at/gadermaier/argon2/Argon2Factory.java deleted file mode 100644 index 3f7f51f..0000000 --- a/src/main/java/at/gadermaier/argon2/Argon2Factory.java +++ /dev/null @@ -1,7 +0,0 @@ -package at.gadermaier.argon2; - -public class Argon2Factory { - public static Argon2 create(){ - return new Argon2(); - } -} diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java b/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java index 53b424c..73e94c6 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java @@ -7,18 +7,17 @@ import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import static at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; public class FillMemory { - public static void fillMemoryBlocks(Instance instance) { + public static void fillMemoryBlocks(Instance instance, ExecutorService executor) { if (instance.getLanes() == 1) { fillMemoryBlockSingleThreaded(instance); } else { - fillMemoryBlockMultiThreaded(instance); + fillMemoryBlockMultiThreaded(instance, executor); } } @@ -31,9 +30,8 @@ private static void fillMemoryBlockSingleThreaded(Instance instance) { } } - private static void fillMemoryBlockMultiThreaded(final Instance instance) { + private static void fillMemoryBlockMultiThreaded(final Instance instance, ExecutorService executor) { - ExecutorService service = Executors.newFixedThreadPool(instance.getLanes()); List> futures = new ArrayList>(); for (int i = 0; i < instance.getIterations(); i++) { @@ -42,7 +40,7 @@ private static void fillMemoryBlockMultiThreaded(final Instance instance) { final Position position = new Position(i, k, j, 0); - Future future = service.submit(new Runnable() { + Future future = executor.submit(new Runnable() { @Override public void run() { FillSegment.fillSegment(instance, position); @@ -55,8 +53,6 @@ public void run() { joinThreads(instance, futures); } } - - service.shutdownNow(); } private static void joinThreads(Instance instance, List> futures) { diff --git a/src/test/java/Argon2Test.java b/src/test/java/Argon2Test.java index ffd5ebf..ffd525f 100644 --- a/src/test/java/Argon2Test.java +++ b/src/test/java/Argon2Test.java @@ -1,4 +1,4 @@ -import at.gadermaier.argon2.Argon2Factory; +import at.gadermaier.argon2.Argon2; import org.junit.jupiter.api.Test; import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; @@ -112,7 +112,7 @@ private void hashtest(int version, int iterations, int memory, int parallelism, String password, String salt, String passwordRef, String mcfref, int outputLength) { - String result = Argon2Factory.create() + String result = new Argon2() .setVersion(version) .setIterations(iterations) .setMemory(memory) diff --git a/src/test/java/InitializeTest.java b/src/test/java/InitializeTest.java index 18f159d..570ee5f 100644 --- a/src/test/java/InitializeTest.java +++ b/src/test/java/InitializeTest.java @@ -1,5 +1,4 @@ import at.gadermaier.argon2.Argon2; -import at.gadermaier.argon2.Argon2Factory; import at.gadermaier.argon2.algorithm.Initialize; import at.gadermaier.argon2.model.Instance; import org.junit.jupiter.api.BeforeEach; @@ -11,14 +10,12 @@ public class InitializeTest { private String instanceNull = "0011a4db4b4dc5422bfab9973caf41bd78d9b20f9a01c236e329c65ffa67c2e6d655eada0eddbc82fe29d0a8fc33ca267e76889ac563e5fcf2a61cb395bd32404a9f9f6bed4324328e4671614efd85ebaa3ff319a4b5996c3fb04e85188839580c945aa12081d3496c6f9a25bf3214d0f766e54c372361a0f3d62ad7acc5cb0306b8fca890e0fcdf932597e3f819ff1ae836976dae0af12b8d53036d1cff4b3bbf5a25de57828ed2de7baa364f0b32ff3ce0626c7cb1e3b76d9bf9a7857e051c1c7a3368792fa1a01a79a7b6c83f97a2cfb3c40c9a7c5f3616673f1f97716a10c6e27a950fb737aab6c544ab59bff3f328a13acf432942c0096420ac7a1ed2de34c181aaf71802ed9a56184476b983e011a50a6203f628d9028d1b442c006d95cbe819acc754451862eab50d7df1ec6ac6bcd55169a7c64f00a3305609df52a178498c44e1d11adf56661e600eeeaf5132864fb99e937cfd3173141e3e619451f1b774719fe6c9d16a73edad3fd494e7520cdefe9e77e210ae2bff00d398e91d6a387775e0a6d9806dc88fa4c481bf4968565cd82df21d135d3bba1cb64c6b65a99d56dd55143f6658d99a5e2c6768394a1036e9cf32fdbaaf704a28d6671423ceb5b54074eb0bde342d541b597a27bf6eced39c168f47da2650df61f96280c1c0f3b858d51534061180c7185ff5f0293a76be3a165ad547303c81c7a480e9eaeddf7f5770b90c3600535b1b3f4be981c357fe08f8db0405ff7d4bc7e5fa94653038aa72ea2f4d4bbb6eb7e5ac76166c57151f0f9c1d26e0307e0d037119e647d33399e8bd0a66b60d18bd0e53af50658e8288b3e829365743abb199c5c59cc910756eb6eacd2a1d73646e47215998d96458be9b00ebf04fc46cdd651d02339822400b5a9565ba11e4b368fbcbdc6ee047ef6e93e66fc08aa0b24349f929d6d3122f2b96b683d709a9c18f584914df5397cf106076fe63823c63470b4c641a7057cf6a690956b6c03db91133db7620cb5e929204a0771c17ac3edb4778e95cb41173c91db45740e1023493242b684cefa0544e384adc8913c4e7bd4711088c2b87d1b922c59bed69a5afbc241cc270268eab791969e3d4181199295af1562631cc5147f8e17607620d965509623ff65261319f2084fb670e473fa990f2b52a6a3fe9dd9b4630e124d7c1b21df4fe4db64b53d4e8c1be5f50093d271a2a7818518ecb786f3c5d36555d348eb3f26fe7031d491167f1c8cd1974e75eb3a205949b3f8b4be0d7dffdee49069f6fa23bd8dec2d950aad3bacae2d3208d543171868665f9d1d6837dab20672d25a32b6794cfc1492a8cf06dcc142a9ca91dc81f00d20038fd7e26e0af42e2a4727a3b4f7b49a17cf3f660635a18063773e3999c3bda22e749b4cb7da41c455ac3e261d64e992d58e28f8157687c5ace8d26349544b3"; - private Argon2 argon2; @BeforeEach public void setUp(){ - argon2 = Argon2Factory.create() - .setPassword("password".toCharArray()) - .setSalt("saltsalt"); + argon2 = new Argon2().setPassword("password".toCharArray()) + .setSalt("saltsalt"); } @Test From 3cf847f8253f8a0d2853f2af52324587d6e56c35 Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sat, 16 Feb 2019 22:12:39 +0900 Subject: [PATCH 03/23] wip --- README.md | 18 ++++++++++ .../java/at/gadermaier/argon2/Argon2.java | 34 +++++++++++++++++-- src/test/java/Argon2Test.java | 2 +- src/test/java/InitializeTest.java | 5 +-- 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6b71855..e45a6b2 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,24 @@ Fork of [https://github.com/andreas1327250/argon2-java]() * Refactored to be used as a library * Removed commons-cli + +```java +public class Example { + + private static final ExecutorService executor = Executors.newCachedThreadPool(); + + public static void example1() { + + String password = "password"; + String salt = "somesalt"; + + Argon2 hasher = Argon2.create().setExecutor(executor); + byte[] hash = hasher.hashAsBytes(password, salt); + } +} +``` + + License: MIT (Same as original) diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index 79a0b90..edb8bab 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -10,6 +10,7 @@ import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -40,9 +41,13 @@ public class Argon2 { private boolean encodedOnly = false; private boolean rawOnly = false; - private ExecutorService executor = Executors.newCachedThreadPool(); + private ExecutorService executor; - public Argon2() { + private static final class ExecutorHolder { + private static final ExecutorService executor = Executors.newCachedThreadPool(); + } + + Argon2() { this.lanes = LANES_DEF; this.outputLength = OUTLEN_DEF; this.memory = 1 << LOG_M_COST_DEF; @@ -51,6 +56,10 @@ public Argon2() { this.type = TYPE_DEF; } + public static Argon2 create() { + return new Argon2(); + } + private static byte[] toByteArray(char[] chars, Charset charset) { assert chars != null; @@ -76,6 +85,13 @@ public String hash(char[] password, String salt){ return hash(); } + public String hash(String password, String salt) { + setPassword( password.getBytes( charset ) ); + setSalt( salt ); + + return hash(); + } + public String hash() { try { argon2_hash(); @@ -86,6 +102,11 @@ public String hash() { } private void argon2_hash() { + + if (executor == null) { + executor = ExecutorHolder.executor; + } + Validation.validateInput(this); long start = System.nanoTime(); @@ -283,4 +304,13 @@ public void setRawOnly(boolean rawOnly) { public String getEncoded() { return ""; //TODO } + + public Executor getExecutor() { + return executor; + } + + public Argon2 setExecutor(ExecutorService executor) { + this.executor = executor; + return this; + } } diff --git a/src/test/java/Argon2Test.java b/src/test/java/Argon2Test.java index ffd525f..605dd9b 100644 --- a/src/test/java/Argon2Test.java +++ b/src/test/java/Argon2Test.java @@ -112,7 +112,7 @@ private void hashtest(int version, int iterations, int memory, int parallelism, String password, String salt, String passwordRef, String mcfref, int outputLength) { - String result = new Argon2() + String result = Argon2.create() .setVersion(version) .setIterations(iterations) .setMemory(memory) diff --git a/src/test/java/InitializeTest.java b/src/test/java/InitializeTest.java index 570ee5f..560d1bf 100644 --- a/src/test/java/InitializeTest.java +++ b/src/test/java/InitializeTest.java @@ -14,8 +14,9 @@ public class InitializeTest { @BeforeEach public void setUp(){ - argon2 = new Argon2().setPassword("password".toCharArray()) - .setSalt("saltsalt"); + argon2 = Argon2.create() + .setPassword("password".toCharArray()) + .setSalt("saltsalt"); } @Test From 1a3f0fd338758a5a1ac8d673592d6a51e4e5e25d Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sun, 17 Feb 2019 17:39:48 +0900 Subject: [PATCH 04/23] added tests --- build.gradle | 6 +- .../java/at/gadermaier/argon2/Argon2.java | 79 +---- .../at/gadermaier/argon2/Argon2Result.java | 66 +++++ src/main/java/at/gadermaier/argon2/Util.java | 22 +- src/test/java/Argon2Test.java | 278 +++++++++++------- 5 files changed, 271 insertions(+), 180 deletions(-) create mode 100644 src/main/java/at/gadermaier/argon2/Argon2Result.java diff --git a/build.gradle b/build.gradle index 7da8646..f0e67b4 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ repositories { dependencies { // compile( -// 'com.google.guava:guava:27.0.1-jre', + compile 'com.google.guava:guava:27.0.1-jre' // TODO implement Base64 encoder // 'com.google.code.findbugs:jsr305:3.0.2', // 'com.google.code.gson:gson:2.8.5', // 'com.google.mug:mug:1.12', @@ -39,8 +39,8 @@ test { useJUnitPlatform() } -sourceCompatibility = 1.6 -targetCompatibility = 1.6 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 compileJava { options.encoding = 'UTF-8' diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index edb8bab..363ac75 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -6,8 +6,6 @@ import at.gadermaier.argon2.model.Argon2Type; import at.gadermaier.argon2.model.Instance; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.concurrent.Executor; @@ -15,13 +13,14 @@ import java.util.concurrent.Executors; import static at.gadermaier.argon2.Constants.Defaults.*; +import static at.gadermaier.argon2.Util.clearArray; +import static at.gadermaier.argon2.Util.toByteArray; public class Argon2 { private byte[] output; private int outputLength; // -l N - private double duration; private byte[] password; private byte[] salt; @@ -38,16 +37,13 @@ public class Argon2 { private boolean clearMemory = true; private Charset charset = Charset.forName("UTF-8"); - private boolean encodedOnly = false; - private boolean rawOnly = false; - private ExecutorService executor; private static final class ExecutorHolder { private static final ExecutorService executor = Executors.newCachedThreadPool(); } - Argon2() { + private Argon2() { this.lanes = LANES_DEF; this.outputLength = OUTLEN_DEF; this.memory = 1 << LOG_M_COST_DEF; @@ -60,42 +56,36 @@ public static Argon2 create() { return new Argon2(); } - private static byte[] toByteArray(char[] chars, Charset charset) { - assert chars != null; - - CharBuffer charBuffer = CharBuffer.wrap(chars); - ByteBuffer byteBuffer = charset.encode(charBuffer); - byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), - byteBuffer.position(), byteBuffer.limit()); - Arrays.fill(byteBuffer.array(), (byte) 0); - return bytes; + public static Argon2 createFromEncoded( String encoded ) { + throw new UnsupportedOperationException(); // TODO } - public String hash(byte[] password, byte[] salt){ + public Argon2Result hash(byte[] password, byte[] salt){ setPassword(password); setSalt(salt); return hash(); } - public String hash(char[] password, String salt){ + public Argon2Result hash(char[] password, String salt){ setPassword(password); setSalt(salt); return hash(); } - public String hash(String password, String salt) { + public Argon2Result hash(String password, String salt) { setPassword( password.getBytes( charset ) ); setSalt( salt ); return hash(); } - public String hash() { + public Argon2Result hash() { try { + byte[] keepSalt = Arrays.copyOf( salt, salt.length ); argon2_hash(); - return getOutputString(); + return new Argon2Result( type, version, memory, iterations, lanes, keepSalt, output ); } finally { clear(); } @@ -109,45 +99,18 @@ private void argon2_hash() { Validation.validateInput(this); - long start = System.nanoTime(); - Instance instance = new Instance(this); Initialize.initialize(instance, this); FillMemory.fillMemoryBlocks(instance, executor); Finalize.finalize(instance, this); - - duration = (System.nanoTime() - start) / 1000000000.0; } public void clear() { - if(password != null) - Arrays.fill(password, 0, password.length-1, (byte)0); - - if(salt != null) - Arrays.fill(salt, 0, salt.length-1, (byte)0); - - if(secret != null) - Arrays.fill(secret, 0, secret.length-1, (byte)0); - - if(additional != null) - Arrays.fill(additional, 0, additional.length-1, (byte)0); - } - - void printSummary(){ - if(encodedOnly) - System.out.println(getEncoded()); - else if(rawOnly) - System.out.println(getOutputString()); - else { - System.out.println("Type:\t\t" + type); - System.out.println("Iterations:\t" + iterations); - System.out.println("Memory:\t\t" + memory + " KiB"); - System.out.println("Parallelism:\t" + lanes); - System.out.println("Hash:\t\t" + getOutputString()); - System.out.println("Encoded:\t " + getEncoded()); - System.out.println(duration + " seconds"); - } + clearArray( password ); + clearArray( salt ); + clearArray( secret ); + clearArray( additional ); } public Argon2 setMemoryInKiB(int memory) { @@ -293,18 +256,6 @@ public Charset getCharset() { return charset; } - public void setEncodedOnly(boolean encodedOnly) { - this.encodedOnly = encodedOnly; - } - - public void setRawOnly(boolean rawOnly) { - this.rawOnly = rawOnly; - } - - public String getEncoded() { - return ""; //TODO - } - public Executor getExecutor() { return executor; } diff --git a/src/main/java/at/gadermaier/argon2/Argon2Result.java b/src/main/java/at/gadermaier/argon2/Argon2Result.java new file mode 100644 index 0000000..889aa68 --- /dev/null +++ b/src/main/java/at/gadermaier/argon2/Argon2Result.java @@ -0,0 +1,66 @@ +package at.gadermaier.argon2; + +import at.gadermaier.argon2.model.Argon2Type; +import com.google.common.io.BaseEncoding; + +import java.util.Arrays; + +import static at.gadermaier.argon2.Util.bytesToHexString; + + +public final class Argon2Result { + + private final Argon2Type type; + private final int version; + private final int memoryInKb; + private final int iteration; + private final int paralellism; + private final byte[] salt; + private final byte[] hash; + + Argon2Result( + Argon2Type type, int version, int memoryInKiB, int iteration, int parallelism, byte[] salt, byte[] hash ) { + + this.type = type; + this.version = version; + this.memoryInKb = memoryInKiB; + this.iteration = iteration; + this.paralellism = parallelism; + this.salt = Arrays.copyOf( salt, salt.length ); + this.hash = Arrays.copyOf( hash, hash.length ); + } + + public byte[] asByte() { + return Arrays.copyOf( hash, hash.length ); + } + + public String asString() { + return bytesToHexString( hash ); + } + + public String asEncoded() { + + String type = this.type.equals( Argon2Type.Argon2i ) ? "i" : + this.type.equals( Argon2Type.Argon2d ) ? "d" : + this.type.equals( Argon2Type.Argon2id ) ? "id" : null; + String salt = BaseEncoding.base64().omitPadding().encode( this.salt ); + String hash = BaseEncoding.base64().omitPadding().encode( this.hash ); + + return new StringBuilder() + .append( "$argon2" ) + .append( type ) + .append( "$v=" ) + .append( version ) + .append( "$m=" ) + .append( memoryInKb ) + .append( ",t=" ) + .append( iteration ) + .append( ",p=" ) + .append( paralellism ) + .append( "$" ) + .append( salt ) + .append( "$" ) + .append( hash ) + .toString(); + } +} diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 5566292..677426b 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -1,5 +1,11 @@ package at.gadermaier.argon2; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.util.Arrays; + + public class Util { public static String bytesToHexString(byte[] bytes) { @@ -58,5 +64,19 @@ public static long intToLong(int x){ return littleEndianBytesToLong(bytes); } -} + static byte[] toByteArray(char[] chars, Charset charset) { + assert chars != null; + CharBuffer charBuffer = CharBuffer.wrap( chars); + ByteBuffer byteBuffer = charset.encode( charBuffer); + byte[] bytes = Arrays.copyOfRange( byteBuffer.array(), + byteBuffer.position(), byteBuffer.limit()); + Arrays.fill(byteBuffer.array(), (byte) 0); + return bytes; + } + + static void clearArray(byte[] arr) { + if (arr != null) + Arrays.fill( arr, 0, arr.length - 1, (byte)0 ); + } +} diff --git a/src/test/java/Argon2Test.java b/src/test/java/Argon2Test.java index 605dd9b..c6eb39c 100644 --- a/src/test/java/Argon2Test.java +++ b/src/test/java/Argon2Test.java @@ -1,127 +1,181 @@ import at.gadermaier.argon2.Argon2; +import at.gadermaier.argon2.Argon2Result; +import at.gadermaier.argon2.model.Argon2Type; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; -import static at.gadermaier.argon2.Constants.Defaults.ARGON2_VERSION_NUMBER; -import static at.gadermaier.argon2.Constants.Defaults.OUTLEN_DEF; -import static org.junit.Assert.fail; +import static at.gadermaier.argon2.Constants.ARGON2_VERSION_13; +import static at.gadermaier.argon2.model.Argon2Type.Argon2i; +import static at.gadermaier.argon2.model.Argon2Type.Argon2id; +import static com.google.common.truth.Truth.assertThat; + public class Argon2Test { @Test - public void basicTest(){ - - boolean largeRam = false; - - int version = ARGON2_VERSION_10; - System.out.println("Test Argon2i version number: " + version); - /* Multiple test cases for various input values */ - hashtest(version, 2, 16, 1, "password", "somesalt", - "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", - "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + - "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", OUTLEN_DEF); - if(largeRam){ - - hashtest(version, 2, 20, 1, "password", "somesalt", - "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9", - "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ" + - "$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk", OUTLEN_DEF); - - hashtest(version, 2, 18, 1, "password", "somesalt", - "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467", - "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ" + - "$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc", OUTLEN_DEF); - } - hashtest(version, 2, 8, 1, "password", "somesalt", - "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06", - "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ" + - "$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY", OUTLEN_DEF); - hashtest(version, 2, 8, 2, "password", "somesalt", - "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb", - "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ" + - "$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs", OUTLEN_DEF); - hashtest(version, 1, 16, 1, "password", "somesalt", - "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2", - "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ" + - "$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI", OUTLEN_DEF); - hashtest(version, 4, 16, 1, "password", "somesalt", - "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b", - "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ" + - "$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs", OUTLEN_DEF); - hashtest(version, 2, 16, 1, "differentpassword", "somesalt", - "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3", - "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + - "$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM", OUTLEN_DEF); - hashtest(version, 2, 16, 1, "password", "diffsalt", - "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497", - "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ" + - "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc", OUTLEN_DEF); - - hashtest(version, 2, 16, 1, "password", "diffsalt", - "1a097a5d1c80e579583f6e19c7e4763ccb7c522ca85b7d58143738e12ca39f8e6e42734c950ff2463675b97c37ba39feba4a9cd9cc5b4c798f2aaf70eb4bd044c8d148decb569870dbd923430b82a083f284beae777812cce18cdac68ee8ccefc6ec9789f30a6b5a034591f51af830f4", - "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ" + - "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc", 112); - - - version = ARGON2_VERSION_NUMBER; - System.out.println("Test Argon2i version number: " + version); - - /* Multiple test cases for various input values */ - hashtest(version, 2, 16, 1, "password", "somesalt", - "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0", - "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + - "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", OUTLEN_DEF); - if(largeRam) { - hashtest(version, 2, 20, 1, "password", "somesalt", - "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41", - "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ" + - "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E", OUTLEN_DEF); - - hashtest(version, 2, 18, 1, "password", "somesalt", - "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb", - "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ" + - "$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s", OUTLEN_DEF); - } - hashtest(version, 2, 8, 1, "password", "somesalt", - "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f", - "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ" + - "$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8", OUTLEN_DEF); - hashtest(version, 2, 8, 2, "password", "somesalt", - "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61", - "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ" + - "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E", OUTLEN_DEF); - hashtest(version, 1, 16, 1, "password", "somesalt", - "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf", - "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ" + - "$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8", OUTLEN_DEF); - hashtest(version, 4, 16, 1, "password", "somesalt", - "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b", - "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ" + - "$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls", OUTLEN_DEF); - hashtest(version, 2, 16, 1, "differentpassword", "somesalt", - "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee", - "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + - "$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4", OUTLEN_DEF); - hashtest(version, 2, 16, 1, "password", "diffsalt", - "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271", - "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ" + - "$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE", OUTLEN_DEF); + public void testI10() { + testHash( Argon2i, ARGON2_VERSION_10, 2, 16, 1, 32, "password", "somesalt", + "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", + "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ" + ); + testHash( Argon2i, ARGON2_VERSION_10, 2, 18, 1, 32, "password", "somesalt", + "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467", + "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ" + + "$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc" + ); + testHash( Argon2i, ARGON2_VERSION_10, 2, 8, 1, 32, "password", "somesalt", + "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06", + "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ" + + "$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY" + ); + testHash( Argon2i, ARGON2_VERSION_10, 2, 8, 2, 32, "password", "somesalt", + "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb", + "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ" + + "$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs" + ); + testHash( Argon2i, ARGON2_VERSION_10, 1, 16, 1, 32, "password", "somesalt", + "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2", + "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ" + + "$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI" + ); + testHash( Argon2i, ARGON2_VERSION_10, 4, 16, 1, 32, "password", "somesalt", + "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b", + "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ" + + "$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs" + ); + testHash( Argon2i, ARGON2_VERSION_10, 2, 16, 1, 32, "differentpassword", "somesalt", + "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3", + "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM" + ); + testHash( Argon2i, ARGON2_VERSION_10, 2, 16, 1, 32, "password", "diffsalt", + "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497", + "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ" + + "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc" + ); } - private void hashtest(int version, int iterations, int memory, int parallelism, - String password, String salt, String passwordRef, String mcfref, int outputLength) { + @Test + void testI13() { + testHash( Argon2i, ARGON2_VERSION_13, 2, 16, 1, 32, "password", "somesalt", + "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0", + "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 18, 1, 32, "password", "somesalt", + "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb", + "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ" + + "$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 8, 1, 32, "password", "somesalt", + "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f", + "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ" + + "$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 8, 2, 32, "password", "somesalt", + "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61", + "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ" + + "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E" + ); + testHash( Argon2i, ARGON2_VERSION_13, 1, 16, 1, 32, "password", "somesalt", + "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf", + "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ" + + "$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8" + ); + testHash( Argon2i, ARGON2_VERSION_13, 4, 16, 1, 32, "password", "somesalt", + "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b", + "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ" + + "$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 16, 1, 32, "differentpassword", "somesalt", + "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee", + "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 16, 1, 32, "password", "diffsalt", + "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271", + "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ" + + "$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE" + ); + } + @Test + void testID13() { + + testHash( Argon2id, ARGON2_VERSION_13, 2, 16, 1, 32, "password", "somesalt", + "09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7", + "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc" + ); + testHash( Argon2id, ARGON2_VERSION_13, 2, 18, 1, 32, "password", "somesalt", + "78fe1ec91fb3aa5657d72e710854e4c3d9b9198c742f9616c2f085bed95b2e8c", + "$argon2id$v=19$m=262144,t=2,p=1$c29tZXNhbHQ" + + "$eP4eyR+zqlZX1y5xCFTkw9m5GYx0L5YWwvCFvtlbLow" + ); + testHash( Argon2id, ARGON2_VERSION_13, 2, 8, 1, 32, "password", "somesalt", + "9dfeb910e80bad0311fee20f9c0e2b12c17987b4cac90c2ef54d5b3021c68bfe", + "$argon2id$v=19$m=256,t=2,p=1$c29tZXNhbHQ" + + "$nf65EOgLrQMR/uIPnA4rEsF5h7TKyQwu9U1bMCHGi/4" + ); + testHash( Argon2id, ARGON2_VERSION_13, 2, 8, 2, 32, "password", "somesalt", + "6d093c501fd5999645e0ea3bf620d7b8be7fd2db59c20d9fff9539da2bf57037", + "$argon2id$v=19$m=256,t=2,p=2$c29tZXNhbHQ" + + "$bQk8UB/VmZZF4Oo79iDXuL5/0ttZwg2f/5U52iv1cDc" + ); + testHash( Argon2id, ARGON2_VERSION_13, 1, 16, 1, 32, "password", "somesalt", + "f6a5adc1ba723dddef9b5ac1d464e180fcd9dffc9d1cbf76cca2fed795d9ca98", + "$argon2id$v=19$m=65536,t=1,p=1$c29tZXNhbHQ" + + "$9qWtwbpyPd3vm1rB1GThgPzZ3/ydHL92zKL+15XZypg" + ); + testHash( Argon2id, ARGON2_VERSION_13, 4, 16, 1, 32, "password", "somesalt", + "9025d48e68ef7395cca9079da4c4ec3affb3c8911fe4f86d1a2520856f63172c", + "$argon2id$v=19$m=65536,t=4,p=1$c29tZXNhbHQ" + + "$kCXUjmjvc5XMqQedpMTsOv+zyJEf5PhtGiUghW9jFyw" + ); + testHash( Argon2id, ARGON2_VERSION_13, 2, 16, 1, 32, "differentpassword", "somesalt", + "0b84d652cf6b0c4beaef0dfe278ba6a80df6696281d7e0d2891b817d8c458fde", + "$argon2id$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + + "$C4TWUs9rDEvq7w3+J4umqA32aWKB1+DSiRuBfYxFj94" + ); + testHash( Argon2id, ARGON2_VERSION_13, 2, 16, 1, 32, "password", "diffsalt", + "bdf32b05ccc42eb15d58fd19b1f856b113da1e9a5874fdcc544308565aa8141c", + "$argon2id$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ" + + "$vfMrBczELrFdWP0ZsfhWsRPaHppYdP3MVEMIVlqoFBw" + ); + } - String result = Argon2.create() - .setVersion(version) - .setIterations(iterations) - .setMemory(memory) - .setParallelism(parallelism) - .setOutputLength(outputLength) - .hash(password.toCharArray(), salt); + @EnabledIfSystemProperty( named = "LARGE_RAM",matches = "true") + @Test + void testLargeRam() { + + testHash( Argon2i, ARGON2_VERSION_10, 2, 20, 1, 32, "password", "somesalt", + "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9", + "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ" + + "$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk" + ); + testHash( Argon2i, ARGON2_VERSION_13, 2, 20, 1, 32, "password", "somesalt", + "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41", + "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ" + + "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E" + ); + } - if (!result.equals(passwordRef)) { - fail(); - } + private void testHash( + Argon2Type type, int version, int iterations, int memory, int parallelism, int outputLength, + String password, String salt, String passwordRef, String mcfref ) { + + Argon2Result result = Argon2.create() + .setType( type ) + .setVersion( version ) + .setIterations( iterations ) + .setMemory( memory ) + .setParallelism( parallelism ) + .setOutputLength( outputLength ) + .hash( password.toCharArray(), salt ); + + assertThat( result.asString() ).isEqualTo( passwordRef ); +// assertThat( result.asEncoded() ).isEqualTo( mcfref ); } } From c5e7ae5f566d5737f95cffdb7383fe79b9065d7c Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sun, 17 Feb 2019 20:22:13 +0900 Subject: [PATCH 05/23] encode --- README.md | 11 +++---- .../java/at/gadermaier/argon2/Argon2.java | 29 ++++++++++++++++++- src/test/java/Argon2Test.java | 5 ++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e45a6b2..9807da9 100644 --- a/README.md +++ b/README.md @@ -6,16 +6,13 @@ Fork of [https://github.com/andreas1327250/argon2-java]() ```java public class Example { - - private static final ExecutorService executor = Executors.newCachedThreadPool(); - + public static void example1() { - + String password = "password"; String salt = "somesalt"; - - Argon2 hasher = Argon2.create().setExecutor(executor); - byte[] hash = hasher.hashAsBytes(password, salt); + + byte[] hash = Argon2.create().hash(password, salt).asBytes(); } } ``` diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index 363ac75..7b3cd66 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -5,6 +5,7 @@ import at.gadermaier.argon2.algorithm.Initialize; import at.gadermaier.argon2.model.Argon2Type; import at.gadermaier.argon2.model.Instance; +import com.google.common.io.BaseEncoding; import java.nio.charset.Charset; import java.util.Arrays; @@ -15,6 +16,7 @@ import static at.gadermaier.argon2.Constants.Defaults.*; import static at.gadermaier.argon2.Util.clearArray; import static at.gadermaier.argon2.Util.toByteArray; +import static at.gadermaier.argon2.model.Argon2Type.*; public class Argon2 { @@ -57,7 +59,32 @@ public static Argon2 create() { } public static Argon2 createFromEncoded( String encoded ) { - throw new UnsupportedOperationException(); // TODO + + String[] parts = encoded.split( "\\$" ); + Argon2Type type = parts[1].endsWith( "i" ) ? Argon2i : + parts[1].endsWith( "d" ) ? Argon2d : + parts[1].endsWith( "id" ) ? Argon2id : null; + boolean hasVersion = !parts[2].startsWith( "m=" ); + String version = hasVersion ? parts[2].split( "=" )[1] : "19"; + String[] paramParts = (hasVersion ? parts[3] : parts[2]).split( "," ); + String m = paramParts[0].split( "=" )[1]; + String t = paramParts[1].split( "=" )[1]; + String p = paramParts[2].split( "=" )[1]; + + String saltEncoded = hasVersion ? parts[4] : parts[3]; + byte[] salt = BaseEncoding.base64().decode( saltEncoded ); + String hashEncoded = hasVersion ? parts[5] : parts[4]; + byte[] hash = BaseEncoding.base64().decode( hashEncoded ); + + Argon2 instance = new Argon2(); + instance.setType( type ); + instance.setVersion( Integer.parseInt( version ) ); + instance.setMemoryInKiB( Integer.parseInt( m ) ); + instance.setIterations( Integer.parseInt( t ) ); + instance.setParallelism( Integer.parseInt( p ) ); + instance.setSalt( salt ); + instance.setOutput( hash ); + return instance; } public Argon2Result hash(byte[] password, byte[] salt){ diff --git a/src/test/java/Argon2Test.java b/src/test/java/Argon2Test.java index c6eb39c..8c265d6 100644 --- a/src/test/java/Argon2Test.java +++ b/src/test/java/Argon2Test.java @@ -11,10 +11,10 @@ import static com.google.common.truth.Truth.assertThat; -public class Argon2Test { +class Argon2Test { @Test - public void testI10() { + void testI10() { testHash( Argon2i, ARGON2_VERSION_10, 2, 16, 1, 32, "password", "somesalt", "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + @@ -176,6 +176,5 @@ private void testHash( .hash( password.toCharArray(), salt ); assertThat( result.asString() ).isEqualTo( passwordRef ); -// assertThat( result.asEncoded() ).isEqualTo( mcfref ); } } From fc42a4775a4d2bd4b410284634695aa5a7dec9ee Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sun, 17 Feb 2019 22:12:50 +0900 Subject: [PATCH 06/23] encode --- README.md | 8 +++ .../java/at/gadermaier/argon2/Argon2.java | 54 +++++++++++-------- src/test/java/Argon2Test.java | 45 ++++++++++++---- src/test/java/InitializeTest.java | 6 ++- 4 files changed, 79 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 9807da9..653b1f4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,14 @@ public class Example { byte[] hash = Argon2.create().hash(password, salt).asBytes(); } + + public static void example2() { + + String password = sendFromUser(); + String encoded = readFromDatabase(); + + boolean result = Argon2().checkHash( encoded, password ); + } } ``` diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index 7b3cd66..0a76c34 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -37,7 +37,7 @@ public class Argon2 { private Argon2Type type; private boolean clearMemory = true; - private Charset charset = Charset.forName("UTF-8"); + private static Charset charset = Charset.forName("UTF-8"); private ExecutorService executor; @@ -58,14 +58,14 @@ public static Argon2 create() { return new Argon2(); } - public static Argon2 createFromEncoded( String encoded ) { + private static Argon2 createFromEncoded( String encoded ) { String[] parts = encoded.split( "\\$" ); - Argon2Type type = parts[1].endsWith( "i" ) ? Argon2i : - parts[1].endsWith( "d" ) ? Argon2d : - parts[1].endsWith( "id" ) ? Argon2id : null; + Argon2Type type = parts[1].endsWith( "id" ) ? Argon2id : + parts[1].endsWith( "i" ) ? Argon2i : + parts[1].endsWith( "d" ) ? Argon2d : null; boolean hasVersion = !parts[2].startsWith( "m=" ); - String version = hasVersion ? parts[2].split( "=" )[1] : "19"; + String version = hasVersion ? parts[2].split( "=" )[1] : "16"; String[] paramParts = (hasVersion ? parts[3] : parts[2]).split( "," ); String m = paramParts[0].split( "=" )[1]; String t = paramParts[1].split( "=" )[1]; @@ -87,6 +87,24 @@ public static Argon2 createFromEncoded( String encoded ) { return instance; } + public static boolean checkHash( String encoded, byte[] password ) { + + Argon2 argon2 = Argon2.createFromEncoded( encoded ); + byte[] expectedHash = Arrays.copyOf( argon2.getOutput(), argon2.getOutput().length ); + argon2.setPassword( password ); + Argon2Result result = argon2.hash(); + + return Arrays.equals( result.asByte(), expectedHash ); + } + + public static boolean checkHash( String encoded, String password ) { + return checkHash( encoded, password.getBytes( charset ) ); + } + + public static boolean checkHash( String encoded, String password, Charset charset ) { + return checkHash( encoded, password.getBytes( charset ) ); + } + public Argon2Result hash(byte[] password, byte[] salt){ setPassword(password); setSalt(salt); @@ -94,16 +112,20 @@ public Argon2Result hash(byte[] password, byte[] salt){ return hash(); } - public Argon2Result hash(char[] password, String salt){ - setPassword(password); - setSalt(salt); + public Argon2Result hash(char[] password, String salt, Charset charset){ + setPassword(toByteArray( password, charset )); + setSalt(salt.getBytes( charset )); return hash(); } public Argon2Result hash(String password, String salt) { + return hash( password, salt, charset ); + } + + public Argon2Result hash(String password, String salt, Charset charset) { setPassword( password.getBytes( charset ) ); - setSalt( salt ); + setSalt( salt.getBytes( charset ) ); return hash(); } @@ -150,14 +172,6 @@ public Argon2 setParallelism(int parallelism){ return this; } - public Argon2 setPassword(char[] password) { - return setPassword(toByteArray(password, charset)); - } - - public Argon2 setSalt(String salt) { - return setSalt(salt.getBytes(charset)); - } - public byte[] getOutput() { return output; } @@ -279,10 +293,6 @@ public void setClearMemory(boolean clearMemory) { this.clearMemory = clearMemory; } - public Charset getCharset() { - return charset; - } - public Executor getExecutor() { return executor; } diff --git a/src/test/java/Argon2Test.java b/src/test/java/Argon2Test.java index 8c265d6..42d852f 100644 --- a/src/test/java/Argon2Test.java +++ b/src/test/java/Argon2Test.java @@ -2,7 +2,7 @@ import at.gadermaier.argon2.Argon2Result; import at.gadermaier.argon2.model.Argon2Type; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; import static at.gadermaier.argon2.Constants.ARGON2_VERSION_13; @@ -146,7 +146,7 @@ void testID13() { ); } - @EnabledIfSystemProperty( named = "LARGE_RAM",matches = "true") + @EnabledIfEnvironmentVariable( named = "LARGE_RAM", matches = "true" ) @Test void testLargeRam() { @@ -162,19 +162,44 @@ void testLargeRam() { ); } + private Argon2Result test( + Argon2Type type, int version, int iterations, int memory, int parallelism, int outputLength, + String password, String salt ) { + + return Argon2.create() + .setType( type ) + .setVersion( version ) + .setIterations( iterations ) + .setMemory( memory ) + .setParallelism( parallelism ) + .setOutputLength( outputLength ) + .hash( password, salt ); + } + private void testHash( Argon2Type type, int version, int iterations, int memory, int parallelism, int outputLength, String password, String salt, String passwordRef, String mcfref ) { - Argon2Result result = Argon2.create() - .setType( type ) - .setVersion( version ) - .setIterations( iterations ) - .setMemory( memory ) - .setParallelism( parallelism ) - .setOutputLength( outputLength ) - .hash( password.toCharArray(), salt ); + assertResult( + test( type, version, iterations, memory, parallelism, outputLength, password, salt ), + password, passwordRef, mcfref + ); + } + private void assertResult( Argon2Result result, String password, String passwordRef, String encoded ) { assertThat( result.asString() ).isEqualTo( passwordRef ); + assertThat( Argon2.checkHash( encoded, password ) ).isTrue(); + } + + @Test + void testEncoded() { + String encoded = test( Argon2i, 19, 3, 12, 1, 32, "password", "somesalt" ).asEncoded(); + assertThat( encoded ).isEqualTo( "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A" ); + + encoded = test( Argon2id, 19, 3, 12, 1, 32, "password", "somesalt" ).asEncoded(); + assertThat( encoded ).isEqualTo( "$argon2id$v=19$m=4096,t=3,p=1$c29tZXNhbHQ$qLml5cbqFAO6YxVHhrSBHP0UWdxrIxkNcM8aMX3blzU" ); + + encoded = test( Argon2id, 16, 4, 16, 4, 32, "password", "somesalt" ).asEncoded(); + assertThat( encoded ).isEqualTo( "$argon2id$v=16$m=65536,t=4,p=4$c29tZXNhbHQ$ZjGrB2S6NxRX2/v18DtFDrfZ3EhCImmES6nAppGsU2w" ); } } diff --git a/src/test/java/InitializeTest.java b/src/test/java/InitializeTest.java index 560d1bf..03acb32 100644 --- a/src/test/java/InitializeTest.java +++ b/src/test/java/InitializeTest.java @@ -4,6 +4,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.nio.charset.Charset; + import static org.junit.jupiter.api.Assertions.assertEquals; @@ -15,8 +17,8 @@ public class InitializeTest { @BeforeEach public void setUp(){ argon2 = Argon2.create() - .setPassword("password".toCharArray()) - .setSalt("saltsalt"); + .setPassword("password".getBytes( Charset.forName( "UTF-8" ) )) + .setSalt("saltsalt".getBytes( Charset.forName( "UTF-8" ) )); } @Test From 5f8cbad9c6424630fb3ee4f2a695112784be97ff Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sun, 17 Feb 2019 22:25:19 +0900 Subject: [PATCH 07/23] removed guava --- README.md | 3 +- build.gradle | 17 +---- .../java/at/gadermaier/argon2/Argon2.java | 70 +++++++++---------- .../at/gadermaier/argon2/Argon2Result.java | 6 +- 4 files changed, 43 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 653b1f4..614f7c5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Fork of [https://github.com/andreas1327250/argon2-java]() +* Java 8+ +* No dependency (removed commons-cli) * Refactored to be used as a library -* Removed commons-cli ```java diff --git a/build.gradle b/build.gradle index f0e67b4..bdfbea7 100644 --- a/build.gradle +++ b/build.gradle @@ -13,23 +13,12 @@ repositories { } dependencies { -// compile( - compile 'com.google.guava:guava:27.0.1-jre' // TODO implement Base64 encoder -// 'com.google.code.findbugs:jsr305:3.0.2', -// 'com.google.code.gson:gson:2.8.5', -// 'com.google.mug:mug:1.12', -// 'com.typesafe:config:1.3.3', -// 'org.slf4j:slf4j-api:1.7.25', -// 'org.slf4j:jul-to-slf4j:1.7.25', // Guava uses java.util.logging -// 'ch.qos.logback:logback-classic:1.2.3' -// ) -// compileOnly 'org.projectlombok:lombok:1.16.20' testCompile( 'org.junit.jupiter:junit-jupiter-api:5.3.2', 'com.google.truth:truth:0.42', - 'com.google.truth.extensions:truth-java8-extension:0.42', - 'org.mockito:mockito-core:2.23.4', - 'rip.deadcode:izvestia:0.2', +// 'com.google.truth.extensions:truth-java8-extension:0.42', +// 'org.mockito:mockito-core:2.23.4', +// 'rip.deadcode:izvestia:0.2', // 'com.google.jimfs:jimfs:1.1' ) testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.3.2' diff --git a/src/main/java/at/gadermaier/argon2/Argon2.java b/src/main/java/at/gadermaier/argon2/Argon2.java index 0a76c34..ffe57c7 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2.java +++ b/src/main/java/at/gadermaier/argon2/Argon2.java @@ -5,10 +5,10 @@ import at.gadermaier.argon2.algorithm.Initialize; import at.gadermaier.argon2.model.Argon2Type; import at.gadermaier.argon2.model.Instance; -import com.google.common.io.BaseEncoding; import java.nio.charset.Charset; import java.util.Arrays; +import java.util.Base64; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -37,7 +37,7 @@ public class Argon2 { private Argon2Type type; private boolean clearMemory = true; - private static Charset charset = Charset.forName("UTF-8"); + private static Charset charset = Charset.forName( "UTF-8" ); private ExecutorService executor; @@ -66,15 +66,15 @@ private static Argon2 createFromEncoded( String encoded ) { parts[1].endsWith( "d" ) ? Argon2d : null; boolean hasVersion = !parts[2].startsWith( "m=" ); String version = hasVersion ? parts[2].split( "=" )[1] : "16"; - String[] paramParts = (hasVersion ? parts[3] : parts[2]).split( "," ); + String[] paramParts = ( hasVersion ? parts[3] : parts[2] ).split( "," ); String m = paramParts[0].split( "=" )[1]; String t = paramParts[1].split( "=" )[1]; String p = paramParts[2].split( "=" )[1]; String saltEncoded = hasVersion ? parts[4] : parts[3]; - byte[] salt = BaseEncoding.base64().decode( saltEncoded ); + byte[] salt = Base64.getDecoder().decode( saltEncoded ); String hashEncoded = hasVersion ? parts[5] : parts[4]; - byte[] hash = BaseEncoding.base64().decode( hashEncoded ); + byte[] hash = Base64.getDecoder().decode( hashEncoded ); Argon2 instance = new Argon2(); instance.setType( type ); @@ -105,25 +105,25 @@ public static boolean checkHash( String encoded, String password, Charset charse return checkHash( encoded, password.getBytes( charset ) ); } - public Argon2Result hash(byte[] password, byte[] salt){ - setPassword(password); - setSalt(salt); + public Argon2Result hash( byte[] password, byte[] salt ) { + setPassword( password ); + setSalt( salt ); return hash(); } - public Argon2Result hash(char[] password, String salt, Charset charset){ - setPassword(toByteArray( password, charset )); - setSalt(salt.getBytes( charset )); + public Argon2Result hash( char[] password, String salt, Charset charset ) { + setPassword( toByteArray( password, charset ) ); + setSalt( salt.getBytes( charset ) ); return hash(); } - public Argon2Result hash(String password, String salt) { + public Argon2Result hash( String password, String salt ) { return hash( password, salt, charset ); } - public Argon2Result hash(String password, String salt, Charset charset) { + public Argon2Result hash( String password, String salt, Charset charset ) { setPassword( password.getBytes( charset ) ); setSalt( salt.getBytes( charset ) ); @@ -142,17 +142,17 @@ public Argon2Result hash() { private void argon2_hash() { - if (executor == null) { + if ( executor == null ) { executor = ExecutorHolder.executor; } - Validation.validateInput(this); + Validation.validateInput( this ); - Instance instance = new Instance(this); + Instance instance = new Instance( this ); - Initialize.initialize(instance, this); - FillMemory.fillMemoryBlocks(instance, executor); - Finalize.finalize(instance, this); + Initialize.initialize( instance, this ); + FillMemory.fillMemoryBlocks( instance, executor ); + Finalize.finalize( instance, this ); } public void clear() { @@ -162,12 +162,12 @@ public void clear() { clearArray( additional ); } - public Argon2 setMemoryInKiB(int memory) { + public Argon2 setMemoryInKiB( int memory ) { this.memory = memory; return this; } - public Argon2 setParallelism(int parallelism){ + public Argon2 setParallelism( int parallelism ) { this.lanes = parallelism; return this; } @@ -176,19 +176,19 @@ public byte[] getOutput() { return output; } - public void setOutput(byte[] finalResult) { + public void setOutput( byte[] finalResult ) { this.output = finalResult; } public String getOutputString() { - return Util.bytesToHexString(output); + return Util.bytesToHexString( output ); } public int getOutputLength() { return outputLength; } - public Argon2 setOutputLength(int outputLength) { + public Argon2 setOutputLength( int outputLength ) { this.outputLength = outputLength; return this; } @@ -197,7 +197,7 @@ public byte[] getPassword() { return password; } - public Argon2 setPassword(byte[] password) { + public Argon2 setPassword( byte[] password ) { this.password = password; return this; } @@ -210,7 +210,7 @@ public byte[] getSalt() { return salt; } - public Argon2 setSalt(byte[] salt) { + public Argon2 setSalt( byte[] salt ) { this.salt = salt; return this; } @@ -223,7 +223,7 @@ public byte[] getSecret() { return secret; } - public Argon2 setSecret(byte[] secret) { + public Argon2 setSecret( byte[] secret ) { this.secret = secret; return this; } @@ -236,20 +236,20 @@ public byte[] getAdditional() { return additional; } - public Argon2 setAdditional(byte[] additional) { + public Argon2 setAdditional( byte[] additional ) { this.additional = additional; return this; } public int getAdditionalLength() { - return additional != null ? additional.length : 0; + return additional != null ? additional.length : 0; } public int getIterations() { return iterations; } - public Argon2 setIterations(int iterations) { + public Argon2 setIterations( int iterations ) { this.iterations = iterations; return this; } @@ -258,7 +258,7 @@ public int getMemory() { return memory; } - public Argon2 setMemory(int memory) { + public Argon2 setMemory( int memory ) { this.memory = 1 << memory; return this; } @@ -271,7 +271,7 @@ public int getVersion() { return version; } - public Argon2 setVersion(int version) { + public Argon2 setVersion( int version ) { this.version = version; return this; } @@ -280,7 +280,7 @@ public Argon2Type getType() { return type; } - public Argon2 setType(Argon2Type type) { + public Argon2 setType( Argon2Type type ) { this.type = type; return this; } @@ -289,7 +289,7 @@ public boolean isClearMemory() { return clearMemory; } - public void setClearMemory(boolean clearMemory) { + public void setClearMemory( boolean clearMemory ) { this.clearMemory = clearMemory; } @@ -297,7 +297,7 @@ public Executor getExecutor() { return executor; } - public Argon2 setExecutor(ExecutorService executor) { + public Argon2 setExecutor( ExecutorService executor ) { this.executor = executor; return this; } diff --git a/src/main/java/at/gadermaier/argon2/Argon2Result.java b/src/main/java/at/gadermaier/argon2/Argon2Result.java index 889aa68..fa5bcca 100644 --- a/src/main/java/at/gadermaier/argon2/Argon2Result.java +++ b/src/main/java/at/gadermaier/argon2/Argon2Result.java @@ -1,9 +1,9 @@ package at.gadermaier.argon2; import at.gadermaier.argon2.model.Argon2Type; -import com.google.common.io.BaseEncoding; import java.util.Arrays; +import java.util.Base64; import static at.gadermaier.argon2.Util.bytesToHexString; @@ -43,8 +43,8 @@ public String asEncoded() { String type = this.type.equals( Argon2Type.Argon2i ) ? "i" : this.type.equals( Argon2Type.Argon2d ) ? "d" : this.type.equals( Argon2Type.Argon2id ) ? "id" : null; - String salt = BaseEncoding.base64().omitPadding().encode( this.salt ); - String hash = BaseEncoding.base64().omitPadding().encode( this.hash ); + String salt = Base64.getEncoder().withoutPadding().encodeToString( this.salt ); + String hash = Base64.getEncoder().withoutPadding().encodeToString( this.hash ); return new StringBuilder() .append( "$argon2" ) From 5dd25f58720742bb5c976e8885c386f28703e619 Mon Sep 17 00:00:00 2001 From: minebreaker Date: Sun, 17 Feb 2019 23:18:08 +0900 Subject: [PATCH 08/23] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 614f7c5..613a55f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ public class Example { public static void example2() { - String password = sendFromUser(); + String password = sentFromUser(); String encoded = readFromDatabase(); boolean result = Argon2().checkHash( encoded, password ); From 77a39cdee638d5c719d56676f3973519c0fb7fee Mon Sep 17 00:00:00 2001 From: dbusche Date: Fri, 26 Apr 2019 19:16:48 +0200 Subject: [PATCH 09/23] Added test to compare Argon2 implementation with the reference implementation argon2-jvm. --- build.gradle | 6 +- src/test/java/TestAgainstReferenceImpl.java | 103 ++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/test/java/TestAgainstReferenceImpl.java diff --git a/build.gradle b/build.gradle index bdfbea7..39198db 100644 --- a/build.gradle +++ b/build.gradle @@ -15,13 +15,17 @@ repositories { dependencies { testCompile( 'org.junit.jupiter:junit-jupiter-api:5.3.2', + 'de.mkammerer:argon2-jvm:2.5', 'com.google.truth:truth:0.42', // 'com.google.truth.extensions:truth-java8-extension:0.42', // 'org.mockito:mockito-core:2.23.4', // 'rip.deadcode:izvestia:0.2', // 'com.google.jimfs:jimfs:1.1' ) - testRuntime 'org.junit.jupiter:junit-jupiter-engine:5.3.2' + testRuntime( + 'org.junit.jupiter:junit-jupiter-engine:5.3.2', + 'de.mkammerer:argon2-jvm:2.5' + ) } test { diff --git a/src/test/java/TestAgainstReferenceImpl.java b/src/test/java/TestAgainstReferenceImpl.java new file mode 100644 index 0000000..28b19ad --- /dev/null +++ b/src/test/java/TestAgainstReferenceImpl.java @@ -0,0 +1,103 @@ +import static at.gadermaier.argon2.Constants.Defaults.OUTLEN_DEF; + +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Random; + +import org.junit.Assert; +import org.junit.Test; + +import at.gadermaier.argon2.Argon2; +import at.gadermaier.argon2.model.Argon2Type; + +/** + * Tests this Argon2 implementation (pure in java) against the implementation + */ +public class TestAgainstReferenceImpl { + + private static Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + @Test + public void testSameHashes() { + for (int i = 1; i < 35; i++) { + System.out.println("Iteration " + i); + Random random = new Random(i); + int iterations = 5 + random.nextInt(11); + int memory = 65536 + random.nextInt(65537); + int parallelism = 1 + random.nextInt(6); + char[] password = new char[1 + random.nextInt(32)]; + for (int j = 0; j < password.length; j++) { + password[j] = (char) (32 + random.nextInt(96)); + } + byte[] salt = new byte[16 + random.nextInt(32)]; + random.nextBytes(salt); + assertEquals(iterations, memory, parallelism, password, salt); + } + } + + private void assertEquals(int iterations, int memory, int parallelism, char[] password, byte[] salt) { + assertEquals(Argon2Type.Argon2id, de.mkammerer.argon2.Argon2Factory.Argon2Types.ARGON2id, iterations, memory, parallelism, password, salt); + assertEquals(Argon2Type.Argon2i, de.mkammerer.argon2.Argon2Factory.Argon2Types.ARGON2i, iterations, memory, parallelism, password, salt); + assertEquals(Argon2Type.Argon2d, de.mkammerer.argon2.Argon2Factory.Argon2Types.ARGON2d, iterations, memory, parallelism, password, salt); + } + + private void assertEquals(Argon2Type type, de.mkammerer.argon2.Argon2Factory.Argon2Types referenceType, int iterations, int memory, int parallelism, + char[] password, byte[] salt) { + int version = 19; + Argon2 argon2 = Argon2.create().setVersion(version).setType(type).setOutputLength(OUTLEN_DEF); + de.mkammerer.argon2.Argon2Advanced referenceArgon2 = de.mkammerer.argon2.Argon2Factory.createAdvanced(referenceType); + + long base = System.currentTimeMillis(); + String referenceHash = referenceHash(referenceArgon2, iterations, memory, parallelism, password, salt); + long timeReferenceHashComputation = System.currentTimeMillis(); + String hash = hash(argon2, iterations, memory, parallelism, password, Arrays.copyOf(salt, salt.length)); + long timeHashComputation = System.currentTimeMillis(); + logTime(timeReferenceHashComputation - base, timeHashComputation - timeReferenceHashComputation); + + Assert.assertEquals("Hash differs.", referenceHash, hash); + } + + private void logTime(long timeReferenceHashComputation, long timeHashComputation) { + StringBuilder msg = new StringBuilder(); + msg.append("Reference implementation ("); + msg.append(toTime(timeReferenceHashComputation)); + msg.append(") - Argon2 implementation ("); + msg.append(toTime(timeHashComputation)); + msg.append("): Overhead "); + msg.append(((((float)timeHashComputation) / timeReferenceHashComputation) -1) * 100); + msg.append("%"); + System.out.println(msg.toString()); + } + + private String hash(Argon2 argon2, int iterations, int memory, int parallelism, char[] password, byte[] salt) { + return argon2.setIterations(iterations) + .setMemoryInKiB(memory) + .setParallelism(parallelism) + .hash(toByteArray(password), salt) + .asEncoded(); + } + + private String referenceHash(de.mkammerer.argon2.Argon2Advanced argon2, int iterations, int memory, int parallelism, char[] password, byte[] salt) { + return argon2.hash(iterations, memory, parallelism, password, DEFAULT_CHARSET, salt); + } + + private byte[] toByteArray(char[] passwd) { + return new String(passwd).getBytes(DEFAULT_CHARSET); + } + + private String toTime(long duration) { + StringBuilder res = new StringBuilder(); + if (duration < 0) { + duration = -duration; + res.append("-"); + } + long s = duration / 1000; + res.append(s); + res.append("s "); + long ms = duration - (s * 1000); + res.append(ms); + res.append("ms"); + return res.toString(); + } + +} From 79ceb6bf031b285ebbfbbbfa963529340c6873d7 Mon Sep 17 00:00:00 2001 From: dbusche Date: Fri, 26 Apr 2019 19:22:08 +0200 Subject: [PATCH 10/23] Fixed class comment. --- src/test/java/TestAgainstReferenceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/TestAgainstReferenceImpl.java b/src/test/java/TestAgainstReferenceImpl.java index 28b19ad..50c6110 100644 --- a/src/test/java/TestAgainstReferenceImpl.java +++ b/src/test/java/TestAgainstReferenceImpl.java @@ -11,7 +11,7 @@ import at.gadermaier.argon2.model.Argon2Type; /** - * Tests this Argon2 implementation (pure in java) against the implementation + * Tests this Argon2 implementation (pure in java) against the implementation "argon2-jvm" in version 2.5. */ public class TestAgainstReferenceImpl { From b9024f02a569497e87fdb478ec3c1f102b048e1c Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 08:48:48 +0200 Subject: [PATCH 11/23] Added main method to invoke benchmark. --- src/test/java/TestAgainstReferenceImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/TestAgainstReferenceImpl.java b/src/test/java/TestAgainstReferenceImpl.java index 50c6110..4d0222c 100644 --- a/src/test/java/TestAgainstReferenceImpl.java +++ b/src/test/java/TestAgainstReferenceImpl.java @@ -1,4 +1,4 @@ -import static at.gadermaier.argon2.Constants.Defaults.OUTLEN_DEF; +import static at.gadermaier.argon2.Constants.Defaults.*; import java.nio.charset.Charset; import java.util.Arrays; @@ -100,4 +100,11 @@ private String toTime(long duration) { return res.toString(); } + /** + * Runs the benchmark from the command line. + */ + public static void main(String[] args) { + new TestAgainstReferenceImpl().testSameHashes(); + } + } From 8239147775721a9e8634b19223dbbfad119f38cb Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 12:16:18 +0200 Subject: [PATCH 12/23] Added memory allocation benchmark. --- src/test/java/TestAgainstReferenceImpl.java | 25 ++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/test/java/TestAgainstReferenceImpl.java b/src/test/java/TestAgainstReferenceImpl.java index 4d0222c..e2abde9 100644 --- a/src/test/java/TestAgainstReferenceImpl.java +++ b/src/test/java/TestAgainstReferenceImpl.java @@ -19,6 +19,7 @@ public class TestAgainstReferenceImpl { @Test public void testSameHashes() { + System.out.println("VM processors: " + Runtime.getRuntime().availableProcessors()); for (int i = 1; i < 35; i++) { System.out.println("Iteration " + i); Random random = new Random(i); @@ -47,23 +48,31 @@ private void assertEquals(Argon2Type type, de.mkammerer.argon2.Argon2Factory.Arg Argon2 argon2 = Argon2.create().setVersion(version).setType(type).setOutputLength(OUTLEN_DEF); de.mkammerer.argon2.Argon2Advanced referenceArgon2 = de.mkammerer.argon2.Argon2Factory.createAdvanced(referenceType); - long base = System.currentTimeMillis(); + System.gc(); + long timeBaseReference = System.currentTimeMillis(); + long memoryBaseReference = Runtime.getRuntime().freeMemory(); String referenceHash = referenceHash(referenceArgon2, iterations, memory, parallelism, password, salt); - long timeReferenceHashComputation = System.currentTimeMillis(); + long memoryReference = memoryBaseReference - Runtime.getRuntime().freeMemory(); + long timeReference = System.currentTimeMillis(); + + System.gc(); + long timeBaseArgon2 = System.currentTimeMillis(); + long memoryBaseArgon2 = Runtime.getRuntime().freeMemory(); String hash = hash(argon2, iterations, memory, parallelism, password, Arrays.copyOf(salt, salt.length)); - long timeHashComputation = System.currentTimeMillis(); - logTime(timeReferenceHashComputation - base, timeHashComputation - timeReferenceHashComputation); - + long memoryArgon2 = memoryBaseArgon2 - Runtime.getRuntime().freeMemory(); + long timeArgon2 = System.currentTimeMillis(); + logTime(timeReference - timeBaseReference, timeArgon2 - timeBaseArgon2); + System.out.println("Memory usage: reference: " + memoryReference + ", argon2: " + memoryArgon2 + ", overhead: " + (((((float)memoryArgon2) / memoryReference) - 1) * 100) + "%"); Assert.assertEquals("Hash differs.", referenceHash, hash); } private void logTime(long timeReferenceHashComputation, long timeHashComputation) { StringBuilder msg = new StringBuilder(); - msg.append("Reference implementation ("); + msg.append("CPU usage: reference: "); msg.append(toTime(timeReferenceHashComputation)); - msg.append(") - Argon2 implementation ("); + msg.append(", argon2: "); msg.append(toTime(timeHashComputation)); - msg.append("): Overhead "); + msg.append(", overhead: "); msg.append(((((float)timeHashComputation) / timeReferenceHashComputation) -1) * 100); msg.append("%"); System.out.println(msg.toString()); From 8ce3656a333bc4e78bc6709af1a4c248ad46a0fc Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:13:59 +0200 Subject: [PATCH 13/23] Simplified int to long conversion. --- src/main/java/at/gadermaier/argon2/Util.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 677426b..1a3d62d 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -58,10 +58,7 @@ public static byte[] longToLittleEndianBytes(long a) { } public static long intToLong(int x){ - byte[] intBytes = intToLittleEndianBytes(x); - byte[] bytes = new byte[8]; - System.arraycopy(intBytes, 0, bytes, 0, 4); - return littleEndianBytesToLong(bytes); + return x & 0xFFFFFFFFL; } static byte[] toByteArray(char[] chars, Charset charset) { From c65a3b8398ef1ce3f2a8a9de7b2a0809ea8325e3 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:26:02 +0200 Subject: [PATCH 14/23] Reduced excessive memory allocation in Block to byte conversion. --- src/main/java/at/gadermaier/argon2/Util.java | 55 ++++++++++++++++--- .../at/gadermaier/argon2/model/Block.java | 11 ++-- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 1a3d62d..544acfd 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -44,19 +44,56 @@ public static byte[] intToLittleEndianBytes(int a) { return result; } - public static byte[] longToLittleEndianBytes(long a) { + public static byte[] longToLittleEndianBytes(long value) { byte[] result = new byte[8]; - result[0] = (byte) (a & 0xFF); - result[1] = (byte) ((a >> 8) & 0xFF); - result[2] = (byte) ((a >> 16) & 0xFF); - result[3] = (byte) ((a >> 24) & 0xFF); - result[4] = (byte) ((a >> 32) & 0xFF); - result[5] = (byte) ((a >> 40) & 0xFF); - result[6] = (byte) ((a >> 48) & 0xFF); - result[7] = (byte) ((a >> 56) & 0xFF); + writeLong(result, 0, value); return result; } + public static int writeLong(byte[] result, int offset, long value) { + result[offset++] = byte0(value); + result[offset++] = byte1(value); + result[offset++] = byte2(value); + result[offset++] = byte3(value); + result[offset++] = byte4(value); + result[offset++] = byte5(value); + result[offset++] = byte6(value); + result[offset++] = byte7(value); + return offset; + } + + private static byte byte0(long value) { + return (byte) (value & 0xFF); + } + + private static byte byte1(long value) { + return (byte) ((value >> 8) & 0xFF); + } + + private static byte byte2(long value) { + return (byte) ((value >> 16) & 0xFF); + } + + private static byte byte3(long value) { + return (byte) ((value >> 24) & 0xFF); + } + + private static byte byte4(long value) { + return (byte) ((value >> 32) & 0xFF); + } + + private static byte byte5(long value) { + return (byte) ((value >> 40) & 0xFF); + } + + private static byte byte6(long value) { + return (byte) ((value >> 48) & 0xFF); + } + + private static byte byte7(long value) { + return (byte) ((value >> 56) & 0xFF); + } + public static long intToLong(int x){ return x & 0xFFFFFFFFL; } diff --git a/src/main/java/at/gadermaier/argon2/model/Block.java b/src/main/java/at/gadermaier/argon2/model/Block.java index b83b508..e17c900 100644 --- a/src/main/java/at/gadermaier/argon2/model/Block.java +++ b/src/main/java/at/gadermaier/argon2/model/Block.java @@ -1,12 +1,11 @@ package at.gadermaier.argon2.model; -import at.gadermaier.argon2.Util; +import static at.gadermaier.argon2.Constants.*; import java.util.Arrays; -import static at.gadermaier.argon2.Constants.ARGON2_BLOCK_SIZE; -import static at.gadermaier.argon2.Constants.ARGON2_QWORDS_IN_BLOCK; +import at.gadermaier.argon2.Util; public class Block { @@ -29,15 +28,15 @@ public void fromBytes(byte[] input) { public byte[] toBytes() { byte[] result = new byte[ARGON2_BLOCK_SIZE]; + int offset = 0; for (int i = 0; i < v.length; i++) { - byte[] bytes = Util.longToLittleEndianBytes(v[i]); - System.arraycopy(bytes, 0, result, i * bytes.length, bytes.length); + offset = Util.writeLong(result, offset, v[i]); } return result; } - public void copyBlock(Block other) { + public void copyBlock(Block other) { System.arraycopy(other.v, 0, v, 0, v.length); } From 67830f923c8a9b958a814324a90264ebcb50cf3e Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:30:47 +0200 Subject: [PATCH 15/23] Refactoring: Extracted flushing from update. --- .../at/gadermaier/argon2/blake2/Blake2b.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java b/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java index 4710923..3cd5da9 100644 --- a/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java +++ b/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java @@ -27,14 +27,14 @@ To the extent possible under law, the author(s) have dedicated all copyright package at.gadermaier.argon2.blake2; +import static at.gadermaier.argon2.blake2.Blake2b.Engine.Assert.*; +import static at.gadermaier.argon2.blake2.Blake2b.Engine.LittleEndian.*; + import java.io.PrintStream; import java.security.Key; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; -import static at.gadermaier.argon2.blake2.Blake2b.Engine.Assert.*; -import static at.gadermaier.argon2.blake2.Blake2b.Engine.LittleEndian.*; - /** */ public interface Blake2b { @@ -415,12 +415,7 @@ final public void reset() { len -= Spec.block_bytes; off += Spec.block_bytes; } - } else if ( buflen == Spec.block_bytes ) { - /* flush */ - this.t[0] += Spec.block_bytes; - this.t[1] += this.t[0] == 0 ? 1 : 0; - compress( buffer, 0 ); - buflen = 0; + } else if (flush()) { continue; } @@ -436,6 +431,23 @@ final public void reset() { } } + /** + * Flushes the {@link #buffer}, if it is full. + * + * @return Whether a flush happened (and the buffer is empty after the operation). + */ + private boolean flush() { + boolean full = buflen == Spec.block_bytes; + if ( full ) { + /* flush */ + this.t[0] += Spec.block_bytes; + this.t[1] += this.t[0] == 0 ? 1 : 0; + compress( buffer, 0 ); + buflen = 0; + } + return full; + } + /** {@inheritDoc} */ @Override final public void update (byte b) { oneByte[0] = b; From eb6100c033abd1933eb26c40763a41e3da943203 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:39:55 +0200 Subject: [PATCH 16/23] Reduced excessive memory allocation in hash initialization. --- src/main/java/at/gadermaier/argon2/Util.java | 29 ++++++++++++++++--- .../argon2/algorithm/Functions.java | 18 ++++++------ .../argon2/algorithm/Initialize.java | 24 +++++++-------- .../at/gadermaier/argon2/blake2/Blake2b.java | 20 +++++++++---- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 544acfd..6e14b19 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -37,13 +37,34 @@ public static long littleEndianBytesToLong(byte[] b) { public static byte[] intToLittleEndianBytes(int a) { byte[] result = new byte[4]; - result[0] = (byte) (a & 0xFF); - result[1] = (byte) ((a >> 8) & 0xFF); - result[2] = (byte) ((a >> 16) & 0xFF); - result[3] = (byte) ((a >> 24) & 0xFF); + writeInt(result, 0, a); return result; } + private static int writeInt(byte[] result, int offset, int value) { + result[offset++] = byte0(value); + result[offset++] = byte1(value); + result[offset++] = byte2(value); + result[offset++] = byte3(value); + return offset; + } + + public static byte byte0(int a) { + return (byte) (a & 0xFF); + } + + public static byte byte1(int a) { + return (byte) ((a >> 8) & 0xFF); + } + + public static byte byte2(int a) { + return (byte) ((a >> 16) & 0xFF); + } + + public static byte byte3(int a) { + return (byte) ((a >> 24) & 0xFF); + } + public static byte[] longToLittleEndianBytes(long value) { byte[] result = new byte[8]; writeLong(result, 0, value); diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java index acf3792..3a713e0 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java @@ -1,11 +1,11 @@ package at.gadermaier.argon2.algorithm; +import static at.gadermaier.argon2.Constants.*; + import at.gadermaier.argon2.Util; import at.gadermaier.argon2.blake2.Blake2b; import at.gadermaier.argon2.model.Block; -import static at.gadermaier.argon2.Constants.*; - class Functions { @@ -13,13 +13,13 @@ class Functions { * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X) * -> 64 byte (ARGON2_PREHASH_DIGEST_LENGTH) */ - static byte[] initialHash(byte[] lanes, byte[] outputLength, - byte[] memory, byte[] iterations, - byte[] version, byte[] type, - byte[] passwordLength, byte[] password, - byte[] saltLength, byte[] salt, - byte[] secretLength, byte[] secret, - byte[] additionalLength, byte[] additional) { + static byte[] initialHash(int lanes, int outputLength, + int memory, int iterations, + int version, int type, + int passwordLength, byte[] password, + int saltLength, byte[] salt, + int secretLength, byte[] secret, + int additionalLength, byte[] additional) { Blake2b.Param params = new Blake2b.Param() diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java index cdd7a0a..eb60966 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java @@ -1,29 +1,29 @@ package at.gadermaier.argon2.algorithm; +import static at.gadermaier.argon2.Constants.*; + import at.gadermaier.argon2.Argon2; import at.gadermaier.argon2.Util; import at.gadermaier.argon2.model.Instance; -import static at.gadermaier.argon2.Constants.*; - public class Initialize { public static void initialize(Instance instance, Argon2 argon2) { byte[] initialHash = Functions.initialHash( - Util.intToLittleEndianBytes(argon2.getLanes()), - Util.intToLittleEndianBytes(argon2.getOutputLength()), - Util.intToLittleEndianBytes(argon2.getMemory()), - Util.intToLittleEndianBytes(argon2.getIterations()), - Util.intToLittleEndianBytes(argon2.getVersion()), - Util.intToLittleEndianBytes(argon2.getType().ordinal()), - Util.intToLittleEndianBytes(argon2.getPasswordLength()), + argon2.getLanes(), + argon2.getOutputLength(), + argon2.getMemory(), + argon2.getIterations(), + argon2.getVersion(), + argon2.getType().ordinal(), + argon2.getPasswordLength(), argon2.getPassword(), - Util.intToLittleEndianBytes(argon2.getSaltLength()), + argon2.getSaltLength(), argon2.getSalt(), - Util.intToLittleEndianBytes(argon2.getSecretLength()), + argon2.getSecretLength(), argon2.getSecret(), - Util.intToLittleEndianBytes(argon2.getAdditionalLength()), + argon2.getAdditionalLength(), argon2.getAdditional() ); fillFirstBlocks(instance, initialHash); diff --git a/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java b/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java index 3cd5da9..76a1646 100644 --- a/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java +++ b/src/main/java/at/gadermaier/argon2/blake2/Blake2b.java @@ -35,6 +35,8 @@ To the extent possible under law, the author(s) have dedicated all copyright import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; +import at.gadermaier.argon2.Util; + /** */ public interface Blake2b { @@ -49,6 +51,9 @@ public interface Blake2b { /** */ void update(byte input); + /** */ + void update(int input); + /** */ void update(byte[] input, int offset, int len); @@ -314,8 +319,6 @@ static class Engine implements Blake2b { * compressor cache buffer offset/cached data length */ private int buflen; - /** to support update(byte) */ - private byte[] oneByte; /** Basic use constructor pending (TODO) JCA/JCE compliance */ Engine() { @@ -331,7 +334,6 @@ static class Engine implements Blake2b { assert param != null : "param is null"; this.param = param; this.buffer = new byte[Spec.block_bytes]; - this.oneByte = new byte[1]; this.outlen = param.getDigestLength(); if (param.getDepth() > Param.Default.depth) { @@ -450,10 +452,18 @@ private boolean flush() { /** {@inheritDoc} */ @Override final public void update (byte b) { - oneByte[0] = b; - update (oneByte, 0, 1); + flush(); + buffer[buflen++] = b; } + /** {@inheritDoc} */ + @Override final public void update (int bytes) { + update(Util.byte0(bytes)); + update(Util.byte1(bytes)); + update(Util.byte2(bytes)); + update(Util.byte3(bytes)); + } + /** {@inheritDoc} */ @Override final public void update(byte[] input) { update (input, 0, input.length); From 822a5dcb6f46006994c3265601b51a0032476e10 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:53:16 +0200 Subject: [PATCH 17/23] Reduced excessive memory allocation in length encoding. --- .../gadermaier/argon2/algorithm/Functions.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java index 3a713e0..57fb7c1 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java @@ -2,7 +2,6 @@ import static at.gadermaier.argon2.Constants.*; -import at.gadermaier.argon2.Util; import at.gadermaier.argon2.blake2.Blake2b; import at.gadermaier.argon2.model.Block; @@ -69,17 +68,15 @@ static byte[] blake2bLong(byte[] input, int outputLength) { assert (input.length == ARGON2_PREHASH_SEED_LENGTH || input.length == ARGON2_BLOCK_SIZE); byte[] result = new byte[outputLength]; - byte[] outlenBytes = Util.intToLittleEndianBytes(outputLength); - int blake2bLength = 64; if (outputLength <= blake2bLength) { - result = blake2b(input, outlenBytes, outputLength); + result = blake2b(input, true, outputLength, outputLength); } else { byte[] outBuffer; /* V1 */ - outBuffer = blake2b(input, outlenBytes, blake2bLength); + outBuffer = blake2b(input, true, outputLength, blake2bLength); System.arraycopy(outBuffer, 0, result, 0, blake2bLength / 2); int r = (outputLength / 32) + (outputLength % 32 == 0 ? 0 : 1) - 2; @@ -87,14 +84,14 @@ static byte[] blake2bLong(byte[] input, int outputLength) { int position = blake2bLength / 2; for (int i = 2; i <= r; i++, position += blake2bLength / 2) { /* V2 to Vr */ - outBuffer = blake2b(outBuffer, null, blake2bLength); + outBuffer = blake2b(outBuffer, false, 0, blake2bLength); System.arraycopy(outBuffer, 0, result, position, blake2bLength / 2); } int lastLength = outputLength - 32 * r; /* Vr+1 */ - outBuffer = blake2b(outBuffer, null, lastLength); + outBuffer = blake2b(outBuffer, false, 0, lastLength); System.arraycopy(outBuffer, 0, result, position, lastLength); } @@ -102,14 +99,15 @@ static byte[] blake2bLong(byte[] input, int outputLength) { return result; } - private static byte[] blake2b(byte[] input, byte[] outlenBytes, int outputLength) { + private static byte[] blake2b(byte[] input, boolean withLen, int outlen, int outputLength) { Blake2b.Param params = new Blake2b.Param() .setDigestLength(outputLength); final Blake2b blake2b = Blake2b.Digest.newInstance(params); - if (outlenBytes != null) - blake2b.update(outlenBytes); + if (withLen) { + blake2b.update(outlen); + } blake2b.update(input); From db13e2fb99e81e1b681fa7a203f0c536949ca044 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 09:55:51 +0200 Subject: [PATCH 18/23] Reduced excessive memory allocation in block initialization. --- src/main/java/at/gadermaier/argon2/Util.java | 2 +- .../java/at/gadermaier/argon2/algorithm/Initialize.java | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 6e14b19..02ec37b 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -41,7 +41,7 @@ public static byte[] intToLittleEndianBytes(int a) { return result; } - private static int writeInt(byte[] result, int offset, int value) { + public static int writeInt(byte[] result, int offset, int value) { result[offset++] = byte0(value); result[offset++] = byte1(value); result[offset++] = byte2(value); diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java index eb60966..9999b22 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java @@ -42,11 +42,8 @@ private static void fillFirstBlocks(Instance instance, byte[] initialHash) { byte[] initialHashWithOnes = getInitialHashLong(initialHash, oneBytes); for (int i = 0; i < instance.getLanes(); i++) { - - byte[] iBytes = Util.intToLittleEndianBytes(i); - - System.arraycopy(iBytes, 0, initialHashWithZeros, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); - System.arraycopy(iBytes, 0, initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); + Util.writeInt(initialHashWithZeros, ARGON2_PREHASH_DIGEST_LENGTH + 4, i); + Util.writeInt(initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4, i); byte[] blockhashBytes = Functions.blake2bLong(initialHashWithZeros, ARGON2_BLOCK_SIZE); instance.memory[i * instance.getLaneLength() + 0].fromBytes(blockhashBytes); From 0cf51e87c543af6a0f5587811b94df08c463c567 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 10:03:54 +0200 Subject: [PATCH 19/23] Reduced excessive memory allocation in Block to byte conversion. --- src/main/java/at/gadermaier/argon2/Util.java | 16 +++++----------- .../java/at/gadermaier/argon2/model/Block.java | 5 +++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/Util.java b/src/main/java/at/gadermaier/argon2/Util.java index 02ec37b..4075789 100644 --- a/src/main/java/at/gadermaier/argon2/Util.java +++ b/src/main/java/at/gadermaier/argon2/Util.java @@ -26,20 +26,14 @@ public static byte[] hexStringToByteArray(String s) { return data; } - public static long littleEndianBytesToLong(byte[] b) { - long result = 0; - for (int i = 7; i >= 0; i--) { + public static long readLong(byte[] buffer, int offset) { + long result = 0; + for (int i = offset + 7; i >= offset; i--) { result <<= 8; - result |= (b[i] & 0xFF); + result |= (buffer[i] & 0xFF); } return result; - } - - public static byte[] intToLittleEndianBytes(int a) { - byte[] result = new byte[4]; - writeInt(result, 0, a); - return result; - } + } public static int writeInt(byte[] result, int offset, int value) { result[offset++] = byte0(value); diff --git a/src/main/java/at/gadermaier/argon2/model/Block.java b/src/main/java/at/gadermaier/argon2/model/Block.java index e17c900..b95e840 100644 --- a/src/main/java/at/gadermaier/argon2/model/Block.java +++ b/src/main/java/at/gadermaier/argon2/model/Block.java @@ -19,9 +19,10 @@ public Block() { public void fromBytes(byte[] input) { assert (input.length == ARGON2_BLOCK_SIZE); + int offset = 0; for (int i = 0; i < v.length; i++) { - byte[] slice = Arrays.copyOfRange(input, i * 8, (i + 1) * 8); - v[i] = Util.littleEndianBytesToLong(slice); + v[i] = Util.readLong(input, offset); + offset += 8; } } From f2d8b33f187fb4254370ed521d851940d7f2609a Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 11:39:04 +0200 Subject: [PATCH 20/23] Reduced excessive temporary block allocation. --- .../argon2/algorithm/FillBlock.java | 9 ++-- .../argon2/algorithm/FillMemory.java | 29 ++++++------ .../argon2/algorithm/FillSegment.java | 46 +++++++++++-------- .../gadermaier/argon2/algorithm/Finalize.java | 4 +- .../argon2/algorithm/Initialize.java | 4 +- .../at/gadermaier/argon2/model/Block.java | 2 +- .../at/gadermaier/argon2/model/Instance.java | 14 ++++-- src/test/java/InitializeTest.java | 15 +++--- 8 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java index 76b414b..ba0342c 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java @@ -3,12 +3,11 @@ import at.gadermaier.argon2.model.Block; class FillBlock { + + private Block R = new Block(); + private Block Z = new Block(); - static void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { - - Block R = new Block(); - Block Z = new Block(); - + void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { R.xor(X, Y); Z.copyBlock(R); diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java b/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java index 73e94c6..9c51dda 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java @@ -1,15 +1,13 @@ package at.gadermaier.argon2.algorithm; -import at.gadermaier.argon2.model.Instance; -import at.gadermaier.argon2.model.Position; +import static at.gadermaier.argon2.Constants.*; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import static at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; +import at.gadermaier.argon2.model.Instance; +import at.gadermaier.argon2.model.Position; public class FillMemory { @@ -22,32 +20,35 @@ public static void fillMemoryBlocks(Instance instance, ExecutorService executor) } private static void fillMemoryBlockSingleThreaded(Instance instance) { + FillSegment worker = new FillSegment(); for (int i = 0; i < instance.getIterations(); i++) { for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { Position position = new Position(i, 0, j, 0); - FillSegment.fillSegment(instance, position); + worker.fillSegment(instance, position); } } } private static void fillMemoryBlockMultiThreaded(final Instance instance, ExecutorService executor) { - List> futures = new ArrayList>(); + Future[] futures = new Future[instance.getLanes()]; + FillSegment[] workers = new FillSegment[instance.getLanes()]; + for (int k = 0; k < instance.getLanes(); k++) { + workers[k] = new FillSegment(); + } for (int i = 0; i < instance.getIterations(); i++) { for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { for (int k = 0; k < instance.getLanes(); k++) { - final Position position = new Position(i, k, j, 0); - - Future future = executor.submit(new Runnable() { + final FillSegment worker = workers[k]; + + futures[k] = executor.submit(new Runnable() { @Override public void run() { - FillSegment.fillSegment(instance, position); + worker.fillSegment(instance, position); } }); - - futures.add(future); } joinThreads(instance, futures); @@ -55,7 +56,7 @@ public void run() { } } - private static void joinThreads(Instance instance, List> futures) { + private static void joinThreads(Instance instance, Future[] futures) { try { for (Future f : futures) { f.get(); diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillSegment.java b/src/main/java/at/gadermaier/argon2/algorithm/FillSegment.java index 4ce31c7..c359e19 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillSegment.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillSegment.java @@ -1,5 +1,7 @@ package at.gadermaier.argon2.algorithm; +import static at.gadermaier.argon2.Constants.*; + import at.gadermaier.argon2.Constants; import at.gadermaier.argon2.Util; import at.gadermaier.argon2.model.Argon2Type; @@ -7,13 +9,17 @@ import at.gadermaier.argon2.model.Instance; import at.gadermaier.argon2.model.Position; -import static at.gadermaier.argon2.Constants.ARGON2_ADDRESSES_IN_BLOCK; -import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; - class FillSegment { - static void fillSegment(Instance instance, Position position) { + private final FillBlock filler = new FillBlock(); + + private final Block _addressBlock = new Block(); + private final Block _zeroBlock = new Block(); + private final Block _inputBlock = new Block(); + + + void fillSegment(Instance instance, Position position) { Block addressBlock = null, inputBlock = null, zeroBlock = null; @@ -23,9 +29,13 @@ static void fillSegment(Instance instance, Position position) { int prevOffset = getPrevOffset(instance, currentOffset); if (dataIndependentAddressing) { - addressBlock = new Block(); - zeroBlock = new Block(); - inputBlock = new Block(); + addressBlock = _addressBlock; + zeroBlock = _zeroBlock; + inputBlock = _inputBlock; + + addressBlock.clear(); + zeroBlock.clear(); + inputBlock.clear(); initAddressBlocks(instance, position, zeroBlock, inputBlock, addressBlock); } @@ -38,12 +48,12 @@ static void fillSegment(Instance instance, Position position) { int refColumn = getRefColumn(instance, position, pseudoRandom, refLane == position.lane); /* 2 Creating a new block */ - Block prevBlock = instance.memory[prevOffset]; - Block refBlock = instance.memory[((instance.getLaneLength()) * refLane + refColumn)]; - Block currentBlock = instance.memory[currentOffset]; + Block prevBlock = instance.memory(prevOffset); + Block refBlock = instance.memory(((instance.getLaneLength()) * refLane + refColumn)); + Block currentBlock = instance.memory(currentOffset); boolean withXor = isWithXor(instance, position); - FillBlock.fillBlock(prevBlock, refBlock, currentBlock, withXor); + filler.fillBlock(prevBlock, refBlock, currentBlock, withXor); } } @@ -55,11 +65,11 @@ private static boolean isDataIndependentAddressing(Instance instance, Position p ); } - private static void initAddressBlocks(Instance instance, Position position, Block zeroBlock, Block inputBlock, Block addressBlock) { + private void initAddressBlocks(Instance instance, Position position, Block zeroBlock, Block inputBlock, Block addressBlock) { inputBlock.v[0] = Util.intToLong(position.pass); inputBlock.v[1] = Util.intToLong(position.lane); inputBlock.v[2] = Util.intToLong(position.slice); - inputBlock.v[3] = Util.intToLong(instance.memory.length); + inputBlock.v[3] = Util.intToLong(instance.memoryLength()); inputBlock.v[4] = Util.intToLong(instance.getIterations()); inputBlock.v[5] = Util.intToLong(instance.getType().ordinal()); @@ -98,22 +108,22 @@ private static int getStartingIndex(Position position) { } } - private static void nextAddresses(Block zeroBlock, Block inputBlock, Block addressBlock) { + private void nextAddresses(Block zeroBlock, Block inputBlock, Block addressBlock) { inputBlock.v[6]++; - FillBlock.fillBlock(zeroBlock, inputBlock, addressBlock, false); - FillBlock.fillBlock(zeroBlock, addressBlock, addressBlock, false); + filler.fillBlock(zeroBlock, inputBlock, addressBlock, false); + filler.fillBlock(zeroBlock, addressBlock, addressBlock, false); } /* 1.2 Computing the index of the reference block */ /* 1.2.1 Taking pseudo-random value from the previous block */ - private static long getPseudoRandom(Instance instance, Position position, Block addressBlock, Block inputBlock, Block zeroBlock, int prevOffset, boolean dataIndependentAddressing) { + private long getPseudoRandom(Instance instance, Position position, Block addressBlock, Block inputBlock, Block zeroBlock, int prevOffset, boolean dataIndependentAddressing) { if (dataIndependentAddressing) { if (position.index % ARGON2_ADDRESSES_IN_BLOCK == 0) { nextAddresses(zeroBlock, inputBlock, addressBlock); } return addressBlock.v[position.index % ARGON2_ADDRESSES_IN_BLOCK]; } else { - return instance.memory[prevOffset].v[0]; + return instance.memory(prevOffset).v[0]; } } diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Finalize.java b/src/main/java/at/gadermaier/argon2/algorithm/Finalize.java index 93911af..c9156c5 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Finalize.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Finalize.java @@ -8,12 +8,12 @@ public class Finalize { public static void finalize(Instance instance, Argon2 argon2) { - Block finalBlock = instance.memory[instance.getLaneLength() - 1]; + Block finalBlock = instance.memory(instance.getLaneLength() - 1); /* XOR the last blocks */ for (int i = 1; i < instance.getLanes(); i++) { int lastBlockInLane = i * instance.getLaneLength() + (instance.getLaneLength() - 1); - finalBlock.xorWith(instance.memory[lastBlockInLane]); + finalBlock.xorWith(instance.memory(lastBlockInLane)); } byte[] finalBlockBytes = finalBlock.toBytes(); diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java index 9999b22..dd51b5f 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Initialize.java @@ -46,10 +46,10 @@ private static void fillFirstBlocks(Instance instance, byte[] initialHash) { Util.writeInt(initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4, i); byte[] blockhashBytes = Functions.blake2bLong(initialHashWithZeros, ARGON2_BLOCK_SIZE); - instance.memory[i * instance.getLaneLength() + 0].fromBytes(blockhashBytes); + instance.memory(i * instance.getLaneLength() + 0).fromBytes(blockhashBytes); blockhashBytes = Functions.blake2bLong(initialHashWithOnes, ARGON2_BLOCK_SIZE); - instance.memory[i * instance.getLaneLength() + 1].fromBytes(blockhashBytes); + instance.memory(i * instance.getLaneLength() + 1).fromBytes(blockhashBytes); } } diff --git a/src/main/java/at/gadermaier/argon2/model/Block.java b/src/main/java/at/gadermaier/argon2/model/Block.java index b95e840..39ab71a 100644 --- a/src/main/java/at/gadermaier/argon2/model/Block.java +++ b/src/main/java/at/gadermaier/argon2/model/Block.java @@ -69,7 +69,7 @@ public String toString() { return result.toString(); } - void clear() { + public void clear() { Arrays.fill(v, 0); } } diff --git a/src/main/java/at/gadermaier/argon2/model/Instance.java b/src/main/java/at/gadermaier/argon2/model/Instance.java index 2c30e33..e9f3c74 100644 --- a/src/main/java/at/gadermaier/argon2/model/Instance.java +++ b/src/main/java/at/gadermaier/argon2/model/Instance.java @@ -1,12 +1,12 @@ package at.gadermaier.argon2.model; -import at.gadermaier.argon2.Argon2; +import static at.gadermaier.argon2.Constants.*; -import static at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; +import at.gadermaier.argon2.Argon2; public class Instance { - public Block[] memory; + private Block[] memory; private int version; private int iterations; private int segmentLength; @@ -53,6 +53,14 @@ public void clear() { memory = null; } + public final int memoryLength() { + return memory.length; + } + + public final Block memory(int index) { + return memory[index]; + } + public Block[] getMemory() { return memory; } diff --git a/src/test/java/InitializeTest.java b/src/test/java/InitializeTest.java index 03acb32..3cd6980 100644 --- a/src/test/java/InitializeTest.java +++ b/src/test/java/InitializeTest.java @@ -1,12 +1,13 @@ -import at.gadermaier.argon2.Argon2; -import at.gadermaier.argon2.algorithm.Initialize; -import at.gadermaier.argon2.model.Instance; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; import java.nio.charset.Charset; -import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import at.gadermaier.argon2.Argon2; +import at.gadermaier.argon2.algorithm.Initialize; +import at.gadermaier.argon2.model.Instance; public class InitializeTest { @@ -27,6 +28,6 @@ public void basicTest(){ Instance instance = new Instance(argon2); Initialize.initialize(instance, argon2); - assertEquals(instanceNull, instance.memory[0].toString()); + assertEquals(instanceNull, instance.memory(0).toString()); } } From a784a48e15e5cbd804b3e9fb7719eb249d21bdcb Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 22:50:33 +0200 Subject: [PATCH 21/23] Moved computations on a single block to Block class. This looks more object-oriented and potentially reduces the number of pointer dereferences during bulk computation. --- .../argon2/algorithm/FillBlock.java | 29 ++---- .../argon2/algorithm/Functions.java | 48 ---------- .../at/gadermaier/argon2/model/Block.java | 91 +++++++++++++++---- 3 files changed, 84 insertions(+), 84 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java index ba0342c..abbc855 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java @@ -9,35 +9,24 @@ class FillBlock { void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { R.xor(X, Y); - Z.copyBlock(R); + Z.copyFrom(R); /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then (16,17,..31)... finally (112,113,...127) */ for (int i = 0; i < 8; i++) { - - Functions.roundFunction(Z, - 16 * i, 16 * i + 1, 16 * i + 2, - 16 * i + 3, 16 * i + 4, 16 * i + 5, - 16 * i + 6, 16 * i + 7, 16 * i + 8, - 16 * i + 9, 16 * i + 10, 16 * i + 11, - 16 * i + 12, 16 * i + 13, 16 * i + 14, - 16 * i + 15 - ); + int i16 = 16 * i; + Z.roundFunction( + i16, i16 + 1, i16 + 2, i16 + 3, i16 + 4, i16 + 5, i16 + 6, i16 + 7, + i16 + 8, i16 + 9, i16 + 10, i16 + 11, i16 + 12, i16 + 13, i16 + 14, i16 + 15); } /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ for (int i = 0; i < 8; i++) { - - Functions.roundFunction(Z, - 2 * i, 2 * i + 1, 2 * i + 16, - 2 * i + 17, 2 * i + 32, 2 * i + 33, - 2 * i + 48, 2 * i + 49, 2 * i + 64, - 2 * i + 65, 2 * i + 80, 2 * i + 81, - 2 * i + 96, 2 * i + 97, 2 * i + 112, - 2 * i + 113 - ); - + int i2 = 2 * i; + Z.roundFunction( + i2, i2 + 1, i2 + 16, i2 + 17, i2 + 32, i2 + 33, i2 + 48, i2 + 49, + i2 + 64, i2 + 65, i2 + 80, i2 + 81, i2 + 96, i2 + 97, i2 + 112, i2 + 113); } if (withXor) { diff --git a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java index 57fb7c1..113aa60 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/Functions.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/Functions.java @@ -3,7 +3,6 @@ import static at.gadermaier.argon2.Constants.*; import at.gadermaier.argon2.blake2.Blake2b; -import at.gadermaier.argon2.model.Block; class Functions { @@ -113,51 +112,4 @@ private static byte[] blake2b(byte[] input, boolean withLen, int outlen, int out return blake2b.digest(); } - - static void roundFunction(Block block, - int v0, int v1, int v2, int v3, - int v4, int v5, int v6, int v7, - int v8, int v9, int v10, int v11, - int v12, int v13, int v14, int v15) { - - F(block, v0, v4, v8, v12); - F(block, v1, v5, v9, v13); - F(block, v2, v6, v10, v14); - F(block, v3, v7, v11, v15); - - F(block, v0, v5, v10, v15); - F(block, v1, v6, v11, v12); - F(block, v2, v7, v8, v13); - F(block, v3, v4, v9, v14); - } - - private static void F(Block block, int a, int b, int c, int d) { - fBlaMka(block, a, b); - rotr64(block, d, a, 32); - - fBlaMka(block, c, d); - rotr64(block, b, c, 24); - - fBlaMka(block, a, b); - rotr64(block, d, a, 16); - - fBlaMka(block, c, d); - rotr64(block, b, c, 63); - } - - /*designed by the Lyra PHC team */ - /* a <- a + b + 2*aL*bL - * + == addition modulo 2^64 - * aL = least 32 bit */ - private static void fBlaMka(Block block, int x, int y) { - final long m = 0xFFFFFFFFL; - final long xy = (block.v[x] & m) * (block.v[y] & m); - - block.v[x] = block.v[x] + block.v[y] + 2 * xy; - } - - private static void rotr64(Block block, int v, int w, long c) { - final long temp = block.v[v] ^ block.v[w]; - block.v[v] = (temp >>> c) | (temp << (64 - c)); - } } diff --git a/src/main/java/at/gadermaier/argon2/model/Block.java b/src/main/java/at/gadermaier/argon2/model/Block.java index 39ab71a..4259ad5 100644 --- a/src/main/java/at/gadermaier/argon2/model/Block.java +++ b/src/main/java/at/gadermaier/argon2/model/Block.java @@ -7,21 +7,26 @@ import at.gadermaier.argon2.Util; -public class Block { +public final class Block { - /* 128 * 8 Byte QWords */ + private static final long MASK = 0xFFFFFFFFL; + + private static final int SIZE = ARGON2_QWORDS_IN_BLOCK; + + /* 128 * 8 Byte QWords */ public long[] v; public Block() { - v = new long[ARGON2_QWORDS_IN_BLOCK]; + v = new long[SIZE]; } public void fromBytes(byte[] input) { assert (input.length == ARGON2_BLOCK_SIZE); int offset = 0; - for (int i = 0; i < v.length; i++) { - v[i] = Util.readLong(input, offset); + long[] v0 = v; + for (int i = 0; i < SIZE; i++) { + v0[i] = Util.readLong(input, offset); offset += 8; } } @@ -30,32 +35,42 @@ public byte[] toBytes() { byte[] result = new byte[ARGON2_BLOCK_SIZE]; int offset = 0; - for (int i = 0; i < v.length; i++) { - offset = Util.writeLong(result, offset, v[i]); + long[] v0 = v; + for (int i = 0; i < SIZE; i++) { + offset = Util.writeLong(result, offset, v0[i]); } return result; } - public void copyBlock(Block other) { - System.arraycopy(other.v, 0, v, 0, v.length); + public void copyFrom(Block other) { + System.arraycopy(other.v, 0, v, 0, SIZE); } public void xor(Block b1, Block b2) { - for (int i = 0; i < v.length; i++) { - v[i] = b1.v[i] ^ b2.v[i]; + long[] v0 = v; + long[] v1 = b1.v; + long[] v2 = b2.v; + for (int i = 0; i < SIZE; i++) { + v0[i] = v1[i] ^ v2[i]; } } public void xor(Block b1, Block b2, Block b3) { - for (int i = 0; i < v.length; i++) { - v[i] = b1.v[i] ^ b2.v[i] ^ b3.v[i]; + long[] v0 = v; + long[] v1 = b1.v; + long[] v2 = b2.v; + long[] v3 = b3.v; + for (int i = 0; i < SIZE; i++) { + v0[i] = v1[i] ^ v2[i] ^ v3[i]; } } - public void xorWith(Block other) { - for (int i = 0; i < v.length; i++) { - v[i] = v[i] ^ other.v[i]; + public void xorWith(Block b1) { + long[] v0 = v; + long[] v1 = b1.v; + for (int i = 0; i < SIZE; i++) { + v0[i] ^= v1[i]; } } @@ -72,5 +87,49 @@ public String toString() { public void clear() { Arrays.fill(v, 0); } + + public final void roundFunction(int v0, int v1, int v2, int v3, int v4, int v5, + int v6, int v7, int v8, int v9, int v10, int v11, int v12, int v13, + int v14, int v15) { + long[] vec = v; + F(vec, v0, v4, v8, v12); + F(vec, v1, v5, v9, v13); + F(vec, v2, v6, v10, v14); + F(vec, v3, v7, v11, v15); + + F(vec, v0, v5, v10, v15); + F(vec, v1, v6, v11, v12); + F(vec, v2, v7, v8, v13); + F(vec, v3, v4, v9, v14); + } + + private static void F(long[] v0, int a, int b, int c, int d) { + fBlaMka(v0, a, b); + rotr64(v0, d, a, 32); + + fBlaMka(v0, c, d); + rotr64(v0, b, c, 24); + + fBlaMka(v0, a, b); + rotr64(v0, d, a, 16); + + fBlaMka(v0, c, d); + rotr64(v0, b, c, 63); + } + + /*designed by the Lyra PHC team */ + /* a <- a + b + 2*aL*bL + * + == addition modulo 2^64 + * aL = least 32 bit */ + private static void fBlaMka(long[] v0, int x, int y) { + final long xy = (v0[x] & MASK) * (v0[y] & MASK); + v0[x] += v0[y] + 2 * xy; + } + + private static void rotr64(long[] v0, int a, int b, int c) { + final long xab = v0[a] ^ v0[b]; + v0[a] = (xab >>> c) | (xab << (64 - c)); + } + } From 6935f81cd368df87a8b147362cced543b5ddd175 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 22:54:30 +0200 Subject: [PATCH 22/23] Removed ugly multiplications. --- .../gadermaier/argon2/algorithm/FillBlock.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java index abbc855..8eb64aa 100644 --- a/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java +++ b/src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java @@ -13,20 +13,18 @@ void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then (16,17,..31)... finally (112,113,...127) */ - for (int i = 0; i < 8; i++) { - int i16 = 16 * i; - Z.roundFunction( - i16, i16 + 1, i16 + 2, i16 + 3, i16 + 4, i16 + 5, i16 + 6, i16 + 7, - i16 + 8, i16 + 9, i16 + 10, i16 + 11, i16 + 12, i16 + 13, i16 + 14, i16 + 15); + for (int i = 0; i < 128; i+=16) { + Z.roundFunction( + i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, + i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15); } /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ - for (int i = 0; i < 8; i++) { - int i2 = 2 * i; - Z.roundFunction( - i2, i2 + 1, i2 + 16, i2 + 17, i2 + 32, i2 + 33, i2 + 48, i2 + 49, - i2 + 64, i2 + 65, i2 + 80, i2 + 81, i2 + 96, i2 + 97, i2 + 112, i2 + 113); + for (int i = 0; i < 16; i+=2) { + Z.roundFunction( + i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, + i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113); } if (withXor) { From c53fa7c17418a4721b3d0748c0c6de2bbbcdb688 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sat, 27 Apr 2019 23:49:43 +0200 Subject: [PATCH 23/23] Updated documentation. --- README.md | 103 ++++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 613a55f..ef5fed2 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,13 @@ -Fork of [https://github.com/andreas1327250/argon2-java]() - -* Java 8+ -* No dependency (removed commons-cli) -* Refactored to be used as a library - - -```java -public class Example { - - public static void example1() { - - String password = "password"; - String salt = "somesalt"; - - byte[] hash = Argon2.create().hash(password, salt).asBytes(); - } - - public static void example2() { - - String password = sentFromUser(); - String encoded = readFromDatabase(); - - boolean result = Argon2().checkHash( encoded, password ); - } -} -``` - - -License: MIT (Same as original) - - -================ ↓↓↓ Original Documentation ↓↓↓ ================ - - # Argon2 Java implementation -This is a pure Java implementation of [Argon2](https://github.com/P-H-C/phc-winner-argon2). It targets Java 6. +This is a pure Java implementation of [Argon2](https://github.com/P-H-C/phc-winner-argon2). It targets Java 8. -Many parts are just taken from the C code and converted to Java syntax - there shouldn't be any major performance bottlenecks anymore, but speed can't keep up quite with the C implementation. +Many parts are just taken from the C code and converted to Java syntax. Runtime overhead compared to the C implementation is within 20 percent. -Fair warning: this code is not well tested and not reviewed. It is not ready for production, use it on your own risk. Same applies for underlying Blake2b implementation. +Fair warning: This code is neither excessively tested nor reviewed. Use it at your own risk. Same applies to the underlying Blake2b cryptographic hash implementation. ## Benchmarks -[Rplots.pdf](benchmarks/Rplots.pdf) +Old benchmark before memory optimization of the Java implementation: [Rplots.pdf](benchmarks/Rplots.pdf) Red is java, green the reference implementation and blue the optimized implementation with SSE-instructions - run on a i7-7700HQ with 16GB RAM. @@ -68,67 +33,59 @@ Clone and install it: ``` - -## Usage +## Usage -``` -// Read password +### Create encoded hash when a user is setting it's password +```java char[] password = readPassword(); - -// Generate salt String salt = generateRandomSalt(); // Hash password - Builder pattern -String hash = Argon2Factory.create() - .setIterations(2) - .setMemory(14) - .setParallelism(1) - .hash(password, salt); - +String encodedHash = Argon2Factory.create() + .setIterations(2) + .setMemory(14) + .setParallelism(1) + .hash(password, salt). + .asEncoded(); + +storeToDataBase(encodedHash); ``` -``` -% java -jar argon2-0.1.jar -usage: argon2 salt [-d | -i | -id] [-e | -r] [-h] [-k | -m ] [-l - ] [-p ] [-t ] --d Use Argon2d instead of Argon2i --e Output only encoded hash --h Print usage --i Use Argon2i (this is the default) --id Use Argon2id instead of Argon2i --k Sets the memory usage of N KiB (default 2^12) --l Sets hash output length to N bytes (default 32) --m Sets the memory usage of 2^N KiB (default 12) --p Sets parallelism to N (default 1) --r Output only the raw bytes of the hash --t Sets the number of iterations to N (default = 3) -Password is read from stdin + +### Verify that a user entered a correct password +```java +String password = readFromUser(); +String encodedHash = readFromDatabase(); + +boolean match = Argon2().checkHash(encodedHash, password); +if (match) { + loginUser(); +} else { + printInvalidUsernameOrPassword(); +} ``` ## Blake2b -The [blake2b Java implementation](https://github.com/alphazero/Blake2b) of [@alphazero](https://github.com/alphazero/) is used. Because no artifact is available on maven central, I copied the relevant class file into this project - for the sake of simplicity. +The [blake2b Java implementation](https://github.com/alphazero/Blake2b) from [@alphazero](https://github.com/alphazero/) is used. Because no artifact is available on Maven Central the relevant class file is embedded in this project. ## License [MIT](https://opensource.org/licenses/MIT) ## TODO * Verification -* Encoded result * Performance + * Can we get closer to the C implementation? * in Block.xorBlock(), the JIT actually already creates vector operations * Fix the build * Build library without commons-dependency, build executable with * maven central * add gradle support -* Add Tests -* .. - +* Add more Tests ## Contact [@andreas1327250](https://github.com/andreas1327250)