├── .gitignore ├── LICENSE ├── README.md ├── benchmarks └── Rplots.pdf ├── pom.xml └── src ├── main └── java │ └── at │ └── gadermaier │ └── argon2 │ ├── Argon2.java │ ├── Argon2ArgumentFactory.java │ ├── Argon2Factory.java │ ├── Benchmark.java │ ├── Constants.java │ ├── Main.java │ ├── Util.java │ ├── Validation.java │ ├── algorithm │ ├── FillBlock.java │ ├── FillMemory.java │ ├── FillSegment.java │ ├── Finalize.java │ ├── Functions.java │ └── Initialize.java │ ├── blake2 │ └── Blake2b.java │ ├── exception │ ├── Argon2Exception.java │ └── Argon2InvalidParameterException.java │ └── model │ ├── Argon2Type.java │ ├── Block.java │ ├── Instance.java │ └── Position.java └── test └── java ├── Argon2Test.java ├── BaseTest.java ├── InitializeTest.java └── MainSuite.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ######################## 3 | # maven specific files # 4 | ######################## 5 | 6 | pom.xml.tag 7 | pom.xml.releaseBackup 8 | pom.xml.versionsBackup 9 | pom.xml.next 10 | release.properties 11 | 12 | ########### 13 | # eclipse # 14 | ########### 15 | 16 | .classpath 17 | .project 18 | .settings/ 19 | 20 | ############ 21 | # intellij # 22 | ############ 23 | 24 | .idea/ 25 | *.iml 26 | *.ipr 27 | *.iws 28 | 29 | ############ 30 | # binaries # 31 | ############ 32 | 33 | target/ 34 | bin/ 35 | out/ 36 | *.class 37 | *.jar 38 | *.war 39 | *.ear 40 | 41 | ######## 42 | # temp # 43 | ######## 44 | 45 | tmp/ 46 | log/ 47 | *.tmp 48 | *.log 49 | *.bak 50 | *.db 51 | 52 | ####### 53 | # mac # 54 | ####### 55 | 56 | .DS_Store 57 | .AppleDouble 58 | .LSOverride 59 | .Spotlight-V100 60 | .Trashes 61 | 62 | ########### 63 | # windows # 64 | ########### 65 | 66 | Thumbs.db 67 | ehthumbs.db 68 | Desktop.ini 69 | $RECYCLE.BIN/ 70 | 71 | ################# 72 | # vm crash-dump # 73 | ################# 74 | 75 | hs_err_pid* 76 | 77 | ################# 78 | # tomcat # 79 | ################# 80 | 81 | tomcat.8080/ 82 | 83 | ################# 84 | # aws # 85 | ################# 86 | 87 | aws.properties 88 | 89 | 90 | .vagrant/ 91 | Vagrantfile 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andreas Gadermaier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Argon2 Java implementation 2 | 3 | This is a pure Java implementation of [Argon2](https://github.com/P-H-C/phc-winner-argon2). It targets Java 6. 4 | 5 | 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. 6 | 7 | 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. 8 | 9 | ## Benchmarks 10 | [Rplots.pdf](benchmarks/Rplots.pdf) 11 | 12 | Red is java, green the reference implementation and blue the optimized implementation with SSE-instructions - run on a i7-7700HQ with 16GB RAM. 13 | 14 | ## Maven 15 | 16 | ### Installation 17 | You need to install the jar into your local `.m2` repository. 18 | 19 | Clone and install it: 20 | 21 | git clone https://github.com/andreas1327250/argon2-java 22 | 23 | cd argon2-java 24 | 25 | mvn install 26 | 27 | 28 | ```xml 29 | 30 | at.gadermaier 31 | argon2 32 | 0.1 33 | 34 | ``` 35 | 36 | 43 | ## Usage 44 | 45 | 46 | ``` 47 | // Read password 48 | char[] password = readPassword(); 49 | 50 | // Generate salt 51 | String salt = generateRandomSalt(); 52 | 53 | // Hash password - Builder pattern 54 | String hash = Argon2Factory.create() 55 | .setIterations(2) 56 | .setMemory(14) 57 | .setParallelism(1) 58 | .hash(password, salt); 59 | 60 | ``` 61 | ``` 62 | % java -jar argon2-0.1.jar 63 | usage: argon2 salt [-d | -i | -id] [-e | -r] [-h] [-k | -m ] [-l 64 | ] [-p ] [-t ] 65 | -d Use Argon2d instead of Argon2i 66 | -e Output only encoded hash 67 | -h Print usage 68 | -i Use Argon2i (this is the default) 69 | -id Use Argon2id instead of Argon2i 70 | -k Sets the memory usage of N KiB (default 2^12) 71 | -l Sets hash output length to N bytes (default 32) 72 | -m Sets the memory usage of 2^N KiB (default 12) 73 | -p Sets parallelism to N (default 1) 74 | -r Output only the raw bytes of the hash 75 | -t Sets the number of iterations to N (default = 3) 76 | Password is read from stdin 77 | ``` 78 | 79 | ## Blake2b 80 | 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. 81 | 82 | ## License 83 | [MIT](https://opensource.org/licenses/MIT) 84 | 85 | ## TODO 86 | * Verification 87 | * Encoded result 88 | * Performance 89 | * in Block.xorBlock(), the JIT actually already creates vector operations 90 | * Fix the build 91 | * Build library without commons-dependency, build executable with 92 | * maven central 93 | * add gradle support 94 | * Add Tests 95 | * .. 96 | 97 | 98 | ## Contact 99 | [@andreas1327250](https://github.com/andreas1327250) 100 | 101 | up.gadermaier@gmail.com 102 | -------------------------------------------------------------------------------- /benchmarks/Rplots.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andreas1327250/argon2-java/c9d270854e0d7a5fcad77bfe252f3c894f0a7671/benchmarks/Rplots.pdf -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | at.gadermaier 8 | argon2 9 | 0.1 10 | 11 | 12 | 13 | commons-cli 14 | commons-cli 15 | 1.3 16 | compile 17 | 18 | 19 | 20 | junit 21 | junit 22 | ${junit.version} 23 | test 24 | 25 | 26 | 27 | org.hamcrest 28 | hamcrest-all 29 | ${hamcrest.version} 30 | test 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | maven-compiler-plugin 39 | 3.0 40 | 41 | 1.6 42 | 1.6 43 | 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-assembly-plugin 49 | 50 | 51 | 52 | at.gadermaier.argon2.Main 53 | 54 | 55 | 56 | 57 | jar-with-dependencies 58 | 59 | false 60 | jar-with-dependencies 61 | 62 | 63 | 64 | make-assembly 65 | package 66 | 67 | single 68 | 69 | 70 | 71 | 72 | 73 | 96 | 97 | 98 | 99 | maven-surefire-plugin 100 | 2.19.1 101 | 102 | alphabetical 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | UTF-8 112 | 4.12 113 | 1.3 114 | 115 | 116 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/Argon2.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2; 2 | 3 | import at.gadermaier.argon2.algorithm.FillMemory; 4 | import at.gadermaier.argon2.algorithm.Finalize; 5 | import at.gadermaier.argon2.algorithm.Initialize; 6 | import at.gadermaier.argon2.model.Argon2Type; 7 | import at.gadermaier.argon2.model.Instance; 8 | 9 | import java.nio.ByteBuffer; 10 | import java.nio.CharBuffer; 11 | import java.nio.charset.Charset; 12 | import java.util.Arrays; 13 | 14 | import static at.gadermaier.argon2.Constants.Defaults.*; 15 | 16 | public class Argon2 { 17 | 18 | private byte[] output; 19 | private int outputLength; // -l N 20 | private double duration; 21 | 22 | private byte[] password; 23 | private byte[] salt; 24 | private byte[] secret; 25 | private byte[] additional; 26 | 27 | private int iterations; // -t N 28 | private int memory; // -m N 29 | private int lanes; // -p N 30 | 31 | private int version; // -v (10/13) 32 | private Argon2Type type; 33 | 34 | private boolean clearMemory = true; 35 | private Charset charset = Charset.forName("UTF-8"); 36 | 37 | private boolean encodedOnly = false; 38 | private boolean rawOnly = false; 39 | 40 | Argon2() { 41 | this.lanes = LANES_DEF; 42 | this.outputLength = OUTLEN_DEF; 43 | this.memory = 1 << LOG_M_COST_DEF; 44 | this.iterations = T_COST_DEF; 45 | this.version = VERSION_DEF; 46 | this.type = TYPE_DEF; 47 | } 48 | 49 | private static byte[] toByteArray(char[] chars, Charset charset) { 50 | assert chars != null; 51 | 52 | CharBuffer charBuffer = CharBuffer.wrap(chars); 53 | ByteBuffer byteBuffer = charset.encode(charBuffer); 54 | byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), 55 | byteBuffer.position(), byteBuffer.limit()); 56 | Arrays.fill(byteBuffer.array(), (byte) 0); 57 | return bytes; 58 | } 59 | 60 | public String hash(byte[] password, byte[] salt){ 61 | setPassword(password); 62 | setSalt(salt); 63 | 64 | return hash(); 65 | } 66 | 67 | public String hash(char[] password, String salt){ 68 | setPassword(password); 69 | setSalt(salt); 70 | 71 | return hash(); 72 | } 73 | 74 | public String hash() { 75 | try { 76 | argon2_hash(); 77 | return getOutputString(); 78 | }finally { 79 | clear(); 80 | } 81 | } 82 | 83 | private void argon2_hash() { 84 | Validation.validateInput(this); 85 | 86 | long start = System.nanoTime(); 87 | 88 | Instance instance = new Instance(this); 89 | 90 | Initialize.initialize(instance, this); 91 | FillMemory.fillMemoryBlocks(instance); 92 | Finalize.finalize(instance, this); 93 | 94 | duration = (System.nanoTime() - start) / 1000000000.0; 95 | } 96 | 97 | public void clear() { 98 | if(password != null) 99 | Arrays.fill(password, 0, password.length-1, (byte)0); 100 | 101 | if(salt != null) 102 | Arrays.fill(salt, 0, salt.length-1, (byte)0); 103 | 104 | if(secret != null) 105 | Arrays.fill(secret, 0, secret.length-1, (byte)0); 106 | 107 | if(additional != null) 108 | Arrays.fill(additional, 0, additional.length-1, (byte)0); 109 | } 110 | 111 | void printSummary(){ 112 | if(encodedOnly) 113 | System.out.println(getEncoded()); 114 | else if(rawOnly) 115 | System.out.println(getOutputString()); 116 | else { 117 | System.out.println("Type:\t\t" + type); 118 | System.out.println("Iterations:\t" + iterations); 119 | System.out.println("Memory:\t\t" + memory + " KiB"); 120 | System.out.println("Parallelism:\t" + lanes); 121 | System.out.println("Hash:\t\t" + getOutputString()); 122 | System.out.println("Encoded:\t " + getEncoded()); 123 | System.out.println(duration + " seconds"); 124 | } 125 | } 126 | 127 | public Argon2 setMemoryInKiB(int memory) { 128 | this.memory = memory; 129 | return this; 130 | } 131 | 132 | public Argon2 setParallelism(int parallelism){ 133 | this.lanes = parallelism; 134 | return this; 135 | } 136 | 137 | public Argon2 setPassword(char[] password) { 138 | return setPassword(toByteArray(password, charset)); 139 | } 140 | 141 | public Argon2 setSalt(String salt) { 142 | return setSalt(salt.getBytes(charset)); 143 | } 144 | 145 | public byte[] getOutput() { 146 | return output; 147 | } 148 | 149 | public void setOutput(byte[] finalResult) { 150 | this.output = finalResult; 151 | } 152 | 153 | public String getOutputString() { 154 | return Util.bytesToHexString(output); 155 | } 156 | 157 | public int getOutputLength() { 158 | return outputLength; 159 | } 160 | 161 | public Argon2 setOutputLength(int outputLength) { 162 | this.outputLength = outputLength; 163 | return this; 164 | } 165 | 166 | public byte[] getPassword() { 167 | return password; 168 | } 169 | 170 | public Argon2 setPassword(byte[] password) { 171 | this.password = password; 172 | return this; 173 | } 174 | 175 | public int getPasswordLength() { 176 | return password.length; 177 | } 178 | 179 | public byte[] getSalt() { 180 | return salt; 181 | } 182 | 183 | public Argon2 setSalt(byte[] salt) { 184 | this.salt = salt; 185 | return this; 186 | } 187 | 188 | public int getSaltLength() { 189 | return salt.length; 190 | } 191 | 192 | public byte[] getSecret() { 193 | return secret; 194 | } 195 | 196 | public Argon2 setSecret(byte[] secret) { 197 | this.secret = secret; 198 | return this; 199 | } 200 | 201 | public int getSecretLength() { 202 | return secret != null ? secret.length : 0; 203 | } 204 | 205 | public byte[] getAdditional() { 206 | return additional; 207 | } 208 | 209 | public Argon2 setAdditional(byte[] additional) { 210 | this.additional = additional; 211 | return this; 212 | } 213 | 214 | public int getAdditionalLength() { 215 | return additional != null ? additional.length : 0; 216 | } 217 | 218 | public int getIterations() { 219 | return iterations; 220 | } 221 | 222 | public Argon2 setIterations(int iterations) { 223 | this.iterations = iterations; 224 | return this; 225 | } 226 | 227 | public int getMemory() { 228 | return memory; 229 | } 230 | 231 | public Argon2 setMemory(int memory) { 232 | this.memory = 1 << memory; 233 | return this; 234 | } 235 | 236 | public int getLanes() { 237 | return lanes; 238 | } 239 | 240 | public int getVersion() { 241 | return version; 242 | } 243 | 244 | public Argon2 setVersion(int version) { 245 | this.version = version; 246 | return this; 247 | } 248 | 249 | public Argon2Type getType() { 250 | return type; 251 | } 252 | 253 | public Argon2 setType(Argon2Type type) { 254 | this.type = type; 255 | return this; 256 | } 257 | 258 | public boolean isClearMemory() { 259 | return clearMemory; 260 | } 261 | 262 | public void setClearMemory(boolean clearMemory) { 263 | this.clearMemory = clearMemory; 264 | } 265 | 266 | public Charset getCharset() { 267 | return charset; 268 | } 269 | 270 | public void setEncodedOnly(boolean encodedOnly) { 271 | this.encodedOnly = encodedOnly; 272 | } 273 | 274 | public void setRawOnly(boolean rawOnly) { 275 | this.rawOnly = rawOnly; 276 | } 277 | 278 | public String getEncoded() { 279 | return ""; //TODO 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/Argon2ArgumentFactory.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2; 2 | 3 | import at.gadermaier.argon2.model.Argon2Type; 4 | import org.apache.commons.cli.*; 5 | 6 | import static java.lang.Integer.parseInt; 7 | 8 | public class Argon2ArgumentFactory { 9 | 10 | static Argon2 parseArguments(String[] args){ 11 | 12 | Options options = buildOptions(); 13 | 14 | CommandLineParser parser = new DefaultParser(); 15 | HelpFormatter formatter = new HelpFormatter(); 16 | CommandLine commandLine = null; 17 | 18 | try { 19 | commandLine = parser.parse(options, args); 20 | 21 | if(commandLine.getArgs().length != 1) 22 | throw new ParseException("no password or salt"); 23 | 24 | return createArgon2(commandLine); 25 | } catch (ParseException e) { 26 | formatter.printHelp("argon2 salt", options,true); 27 | System.out.println("Password is read from stdin"); 28 | 29 | bailOut(); 30 | } 31 | 32 | // not reachable 33 | return null; 34 | } 35 | 36 | private static Argon2 createArgon2(CommandLine commandLine) throws ParseException { 37 | Argon2 argon2 = new Argon2(); 38 | String salt = commandLine.getArgs()[0]; 39 | 40 | argon2.setSalt(salt); 41 | 42 | if(commandLine.hasOption("h")) 43 | throw new ParseException("usage"); 44 | 45 | if(commandLine.hasOption("t")){ 46 | argon2.setIterations(parseInt(commandLine.getOptionValue("t"))); 47 | } 48 | 49 | if(commandLine.hasOption("p")){ 50 | argon2.setParallelism(parseInt(commandLine.getOptionValue("p"))); 51 | } 52 | 53 | if(commandLine.hasOption("m")){ 54 | argon2.setMemory(parseInt(commandLine.getOptionValue("m"))); 55 | }else if(commandLine.hasOption("k")){ 56 | int k = parseInt(commandLine.getOptionValue("k")); 57 | if(k % 4*argon2.getLanes() != 0) 58 | throw new ParseException("k must be a multiple of p*4"); 59 | argon2.setMemoryInKiB(k); 60 | } 61 | 62 | 63 | if(commandLine.hasOption("e")){ 64 | argon2.setEncodedOnly(true); 65 | }else if(commandLine.hasOption("r")){ 66 | argon2.setRawOnly(true); 67 | } 68 | 69 | if(commandLine.hasOption("i")){ 70 | argon2.setType(Argon2Type.Argon2i); 71 | }else if(commandLine.hasOption("d")){ 72 | argon2.setType(Argon2Type.Argon2d); 73 | }else if(commandLine.hasOption("id")){ 74 | argon2.setType(Argon2Type.Argon2id); 75 | } 76 | 77 | if (commandLine.hasOption(("l"))) { 78 | argon2.setOutputLength(parseInt(commandLine.getOptionValue("l"))); 79 | } 80 | 81 | if(commandLine.hasOption("v")){ 82 | int version = parseInt(commandLine.getOptionValue("v")); 83 | if (!(version == 10 || version == 13)) { 84 | bailOut("wrong version"); 85 | } 86 | argon2.setVersion(version); 87 | } 88 | 89 | return argon2; 90 | } 91 | 92 | private static Options buildOptions(){ 93 | Options options = new Options(); 94 | Option option; 95 | 96 | OptionGroup optionGroup = new OptionGroup(); 97 | 98 | option = new Option("i", null, false, "Use Argon2i (this is the default)"); 99 | optionGroup.addOption(option); 100 | option = new Option("d", null, false, "Use Argon2d instead of Argon2i"); 101 | optionGroup.addOption(option); 102 | option = new Option("id", null, false, "Use Argon2id instead of Argon2i"); 103 | optionGroup.addOption(option); 104 | 105 | options.addOptionGroup(optionGroup); 106 | 107 | 108 | option = new Option("t", null, true, "Sets the number of iterations to N (default = 3)"); 109 | option.setArgName("N"); 110 | option.setType(Integer.class); 111 | options.addOption(option); 112 | 113 | optionGroup = new OptionGroup(); 114 | 115 | option = new Option("m", null, true, "Sets the memory usage of 2^N KiB (default 12)"); 116 | option.setArgName("N"); 117 | option.setType(Integer.class); 118 | optionGroup.addOption(option); 119 | 120 | option = new Option("k", null, true, "Sets the memory usage of N KiB (default 2^12)"); 121 | option.setArgName("N"); 122 | option.setType(Integer.class); 123 | optionGroup.addOption(option); 124 | 125 | options.addOptionGroup(optionGroup); 126 | 127 | 128 | option = new Option("p", null, true, "Sets parallelism to N (default 1)"); 129 | option.setArgName("N"); 130 | option.setType(Integer.class); 131 | options.addOption(option); 132 | 133 | option = new Option("l", null, true, "Sets hash output length to N bytes (default 32)"); 134 | option.setArgName("N"); 135 | option.setType(Integer.class); 136 | options.addOption(option); 137 | 138 | 139 | optionGroup = new OptionGroup(); 140 | 141 | option = new Option("e", null, false, "Output only encoded hash"); 142 | optionGroup.addOption(option); 143 | option = new Option("r", null, false, "Output only the raw bytes of the hash"); 144 | optionGroup.addOption(option); 145 | 146 | options.addOptionGroup(optionGroup); 147 | 148 | option = new Option("h", null, false, "Print usage"); 149 | options.addOption(option); 150 | 151 | return options; 152 | } 153 | 154 | private static void bailOut(String message){ 155 | System.out.println(message); 156 | bailOut(); 157 | } 158 | 159 | private static void bailOut(){ 160 | System.exit(1); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/Argon2Factory.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2; 2 | 3 | public class Argon2Factory { 4 | public static Argon2 create(){ 5 | return new Argon2(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/Benchmark.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2; 2 | 3 | import at.gadermaier.argon2.model.Argon2Type; 4 | 5 | import static at.gadermaier.argon2.Constants.Defaults.ARGON2_VERSION_NUMBER; 6 | import static at.gadermaier.argon2.model.Argon2Type.Argon2d; 7 | import static at.gadermaier.argon2.model.Argon2Type.Argon2i; 8 | 9 | public class Benchmark { 10 | 11 | public static void main(String[] args) { 12 | if (args.length > 0) 13 | benchmark(Integer.parseInt(args[0])); 14 | else 15 | benchmark(18); 16 | } 17 | 18 | /* 19 | * Benchmarks Argon2 with salt length 16, password length 16, t_cost 1, 20 | * and different m_cost and threads 21 | */ 22 | private static void benchmark(int maxMemory) { 23 | 24 | System.out.println("threads;memory;seconds"); 25 | 26 | int inlen = 16; 27 | int outlen = 16; 28 | 29 | int t_cost = 3; 30 | int m_cost; 31 | int[] thread_test = new int[]{1, 2, 4, 8}; 32 | Argon2Type[] types = new Argon2Type[]{Argon2i, Argon2d}; 33 | 34 | byte[] pwdBytes = new byte[inlen]; 35 | byte[] saltBytes = new byte[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 36 | 37 | //warmup jit 38 | Argon2Factory.create() 39 | .setIterations(10) 40 | .setParallelism(4) 41 | .hash("password".toCharArray(), "saltsalt"); 42 | 43 | for (m_cost = 10; m_cost <= maxMemory; m_cost++) { 44 | for (int i = 0; i < 4; i++) { 45 | 46 | 47 | double run_time = 0; 48 | int thread_n = thread_test[i]; 49 | 50 | int runs = 3; 51 | run(outlen, t_cost, m_cost, types, pwdBytes, saltBytes, run_time, thread_n, runs); 52 | System.gc(); 53 | } 54 | } 55 | } 56 | 57 | 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) { 58 | for(int averageIndex=0; averageIndex= 0; i--) { 26 | result <<= 8; 27 | result |= (b[i] & 0xFF); 28 | } 29 | return result; 30 | } 31 | 32 | public static byte[] intToLittleEndianBytes(int a) { 33 | byte[] result = new byte[4]; 34 | result[0] = (byte) (a & 0xFF); 35 | result[1] = (byte) ((a >> 8) & 0xFF); 36 | result[2] = (byte) ((a >> 16) & 0xFF); 37 | result[3] = (byte) ((a >> 24) & 0xFF); 38 | return result; 39 | } 40 | 41 | public static byte[] longToLittleEndianBytes(long a) { 42 | byte[] result = new byte[8]; 43 | result[0] = (byte) (a & 0xFF); 44 | result[1] = (byte) ((a >> 8) & 0xFF); 45 | result[2] = (byte) ((a >> 16) & 0xFF); 46 | result[3] = (byte) ((a >> 24) & 0xFF); 47 | result[4] = (byte) ((a >> 32) & 0xFF); 48 | result[5] = (byte) ((a >> 40) & 0xFF); 49 | result[6] = (byte) ((a >> 48) & 0xFF); 50 | result[7] = (byte) ((a >> 56) & 0xFF); 51 | return result; 52 | } 53 | 54 | public static long intToLong(int x){ 55 | byte[] intBytes = intToLittleEndianBytes(x); 56 | byte[] bytes = new byte[8]; 57 | System.arraycopy(intBytes, 0, bytes, 0, 4); 58 | return littleEndianBytesToLong(bytes); 59 | } 60 | 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/Validation.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2; 2 | 3 | import at.gadermaier.argon2.exception.Argon2InvalidParameterException; 4 | 5 | import static at.gadermaier.argon2.Constants.Constraints.*; 6 | import static at.gadermaier.argon2.Constants.Messages.*; 7 | 8 | class Validation { 9 | 10 | static void validateInput(Argon2 argon2){ 11 | String message = null; 12 | 13 | if (argon2.getLanes() < MIN_PARALLELISM) 14 | message = P_MIN_MSG; 15 | else if (argon2.getLanes() > MAX_PARALLELISM) 16 | message = P_MAX_MSG; 17 | else if(argon2.getMemory() < 2 * argon2.getLanes()) 18 | message = M_MIN_MSG; 19 | else if(argon2.getIterations() < MIN_ITERATIONS) 20 | message = T_MIN_MSG; 21 | else if(argon2.getIterations() > MAX_ITERATIONS) 22 | message = T_MAX_MSG; 23 | else if(argon2.getPasswordLength() < MIN_PWD_LENGTH) 24 | message = PWD_MIN_MSG; 25 | else if(argon2.getPasswordLength() > MAX_PWD_LENGTH) 26 | message = PWD_MAX_MSG; 27 | else if(argon2.getSaltLength() < MIN_SALT_LENGTH) 28 | message = SALT_MIN_MSG; 29 | else if(argon2.getSaltLength() > MAX_SALT_LENGTH) 30 | message = SALT_MAX_MSG; 31 | else if(argon2.getSecretLength() > MAX_SECRET_LENGTH) 32 | message = SECRET_MAX_MSG; 33 | else if(argon2.getAdditionalLength() > MAX_AD_LENGTH) 34 | message = ADDITIONAL_MAX_MSG; 35 | 36 | if(message != null) 37 | throw new Argon2InvalidParameterException(message); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/FillBlock.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.model.Block; 4 | 5 | class FillBlock { 6 | 7 | static void fillBlock(Block X, Block Y, Block currentBlock, boolean withXor) { 8 | 9 | Block R = new Block(); 10 | Block Z = new Block(); 11 | 12 | R.xor(X, Y); 13 | Z.copyBlock(R); 14 | 15 | /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then 16 | (16,17,..31)... finally (112,113,...127) */ 17 | for (int i = 0; i < 8; i++) { 18 | 19 | Functions.roundFunction(Z, 20 | 16 * i, 16 * i + 1, 16 * i + 2, 21 | 16 * i + 3, 16 * i + 4, 16 * i + 5, 22 | 16 * i + 6, 16 * i + 7, 16 * i + 8, 23 | 16 * i + 9, 16 * i + 10, 16 * i + 11, 24 | 16 * i + 12, 16 * i + 13, 16 * i + 14, 25 | 16 * i + 15 26 | ); 27 | } 28 | 29 | /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then 30 | (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ 31 | for (int i = 0; i < 8; i++) { 32 | 33 | Functions.roundFunction(Z, 34 | 2 * i, 2 * i + 1, 2 * i + 16, 35 | 2 * i + 17, 2 * i + 32, 2 * i + 33, 36 | 2 * i + 48, 2 * i + 49, 2 * i + 64, 37 | 2 * i + 65, 2 * i + 80, 2 * i + 81, 38 | 2 * i + 96, 2 * i + 97, 2 * i + 112, 39 | 2 * i + 113 40 | ); 41 | 42 | } 43 | 44 | if (withXor) { 45 | currentBlock.xor(R, Z, currentBlock); 46 | } else { 47 | currentBlock.xor(R, Z); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/FillMemory.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.model.Instance; 4 | import at.gadermaier.argon2.model.Position; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.concurrent.ExecutionException; 9 | import java.util.concurrent.ExecutorService; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.Future; 12 | 13 | import static at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; 14 | 15 | public class FillMemory { 16 | 17 | public static void fillMemoryBlocks(Instance instance) { 18 | if (instance.getLanes() == 1) { 19 | fillMemoryBlockSingleThreaded(instance); 20 | } else { 21 | fillMemoryBlockMultiThreaded(instance); 22 | } 23 | } 24 | 25 | private static void fillMemoryBlockSingleThreaded(Instance instance) { 26 | for (int i = 0; i < instance.getIterations(); i++) { 27 | for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { 28 | Position position = new Position(i, 0, j, 0); 29 | FillSegment.fillSegment(instance, position); 30 | } 31 | } 32 | } 33 | 34 | private static void fillMemoryBlockMultiThreaded(final Instance instance) { 35 | 36 | ExecutorService service = Executors.newFixedThreadPool(instance.getLanes()); 37 | List> futures = new ArrayList>(); 38 | 39 | for (int i = 0; i < instance.getIterations(); i++) { 40 | for (int j = 0; j < ARGON2_SYNC_POINTS; j++) { 41 | for (int k = 0; k < instance.getLanes(); k++) { 42 | 43 | final Position position = new Position(i, k, j, 0); 44 | 45 | Future future = service.submit(new Runnable() { 46 | @Override 47 | public void run() { 48 | FillSegment.fillSegment(instance, position); 49 | } 50 | }); 51 | 52 | futures.add(future); 53 | } 54 | 55 | joinThreads(instance, futures); 56 | } 57 | } 58 | 59 | service.shutdownNow(); 60 | } 61 | 62 | private static void joinThreads(Instance instance, List> futures) { 63 | try { 64 | for (Future f : futures) { 65 | f.get(); 66 | } 67 | } catch (InterruptedException e) { 68 | instance.clear(); 69 | throw new RuntimeException(e); 70 | } catch (ExecutionException e) { 71 | instance.clear(); 72 | throw new RuntimeException(e); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/FillSegment.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.Constants; 4 | import at.gadermaier.argon2.Util; 5 | import at.gadermaier.argon2.model.Argon2Type; 6 | import at.gadermaier.argon2.model.Block; 7 | import at.gadermaier.argon2.model.Instance; 8 | import at.gadermaier.argon2.model.Position; 9 | 10 | import static at.gadermaier.argon2.Constants.ARGON2_ADDRESSES_IN_BLOCK; 11 | import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; 12 | 13 | 14 | class FillSegment { 15 | 16 | static void fillSegment(Instance instance, Position position) { 17 | 18 | Block addressBlock = null, inputBlock = null, zeroBlock = null; 19 | 20 | boolean dataIndependentAddressing = isDataIndependentAddressing(instance, position); 21 | int startingIndex = getStartingIndex(position); 22 | int currentOffset = position.lane * instance.getLaneLength() + position.slice * instance.getSegmentLength() + startingIndex; 23 | int prevOffset = getPrevOffset(instance, currentOffset); 24 | 25 | if (dataIndependentAddressing) { 26 | addressBlock = new Block(); 27 | zeroBlock = new Block(); 28 | inputBlock = new Block(); 29 | 30 | initAddressBlocks(instance, position, zeroBlock, inputBlock, addressBlock); 31 | } 32 | 33 | for (position.index = startingIndex; position.index < instance.getSegmentLength(); position.index++, currentOffset++, prevOffset++) { 34 | prevOffset = rotatePrevOffset(instance, currentOffset, prevOffset); 35 | 36 | long pseudoRandom = getPseudoRandom(instance, position, addressBlock, inputBlock, zeroBlock, prevOffset, dataIndependentAddressing); 37 | int refLane = getRefLane(instance, position, pseudoRandom); 38 | int refColumn = getRefColumn(instance, position, pseudoRandom, refLane == position.lane); 39 | 40 | /* 2 Creating a new block */ 41 | Block prevBlock = instance.memory[prevOffset]; 42 | Block refBlock = instance.memory[((instance.getLaneLength()) * refLane + refColumn)]; 43 | Block currentBlock = instance.memory[currentOffset]; 44 | 45 | boolean withXor = isWithXor(instance, position); 46 | FillBlock.fillBlock(prevBlock, refBlock, currentBlock, withXor); 47 | } 48 | } 49 | 50 | private static boolean isDataIndependentAddressing(Instance instance, Position position) { 51 | return (instance.getType() == Argon2Type.Argon2i) || 52 | (instance.getType() == Argon2Type.Argon2id 53 | && (position.pass == 0) 54 | && (position.slice < Constants.ARGON2_SYNC_POINTS / 2) 55 | ); 56 | } 57 | 58 | private static void initAddressBlocks(Instance instance, Position position, Block zeroBlock, Block inputBlock, Block addressBlock) { 59 | inputBlock.v[0] = Util.intToLong(position.pass); 60 | inputBlock.v[1] = Util.intToLong(position.lane); 61 | inputBlock.v[2] = Util.intToLong(position.slice); 62 | inputBlock.v[3] = Util.intToLong(instance.memory.length); 63 | inputBlock.v[4] = Util.intToLong(instance.getIterations()); 64 | inputBlock.v[5] = Util.intToLong(instance.getType().ordinal()); 65 | 66 | if ((position.pass == 0) && (position.slice == 0)) { 67 | /* Don't forget to generate the first block of addresses: */ 68 | nextAddresses(zeroBlock, inputBlock, addressBlock); 69 | } 70 | } 71 | 72 | private static boolean isWithXor(Instance instance, Position position) { 73 | return !(position.pass == 0 || instance.getVersion() == ARGON2_VERSION_10); 74 | } 75 | 76 | private static int getPrevOffset(Instance instance, int currentOffset) { 77 | if (currentOffset % instance.getLaneLength() == 0) { 78 | /* Last block in this lane */ 79 | return currentOffset + instance.getLaneLength() - 1; 80 | } else { 81 | /* Previous block */ 82 | return currentOffset - 1; 83 | } 84 | } 85 | 86 | private static int rotatePrevOffset(Instance instance, int currentOffset, int prevOffset) { 87 | if (currentOffset % instance.getLaneLength() == 1) { 88 | prevOffset = currentOffset - 1; 89 | } 90 | return prevOffset; 91 | } 92 | 93 | private static int getStartingIndex(Position position) { 94 | if ((position.pass == 0) && (position.slice == 0)) { 95 | return 2; /* we have already generated the first two blocks */ 96 | } else { 97 | return 0; 98 | } 99 | } 100 | 101 | private static void nextAddresses(Block zeroBlock, Block inputBlock, Block addressBlock) { 102 | inputBlock.v[6]++; 103 | FillBlock.fillBlock(zeroBlock, inputBlock, addressBlock, false); 104 | FillBlock.fillBlock(zeroBlock, addressBlock, addressBlock, false); 105 | } 106 | 107 | /* 1.2 Computing the index of the reference block */ 108 | /* 1.2.1 Taking pseudo-random value from the previous block */ 109 | private static long getPseudoRandom(Instance instance, Position position, Block addressBlock, Block inputBlock, Block zeroBlock, int prevOffset, boolean dataIndependentAddressing) { 110 | if (dataIndependentAddressing) { 111 | if (position.index % ARGON2_ADDRESSES_IN_BLOCK == 0) { 112 | nextAddresses(zeroBlock, inputBlock, addressBlock); 113 | } 114 | return addressBlock.v[position.index % ARGON2_ADDRESSES_IN_BLOCK]; 115 | } else { 116 | return instance.memory[prevOffset].v[0]; 117 | } 118 | } 119 | 120 | private static int getRefLane(Instance instance, Position position, long pseudoRandom) { 121 | int refLane = (int) (((pseudoRandom >>> 32)) % instance.getLanes()); 122 | 123 | if ((position.pass == 0) && (position.slice == 0)) { 124 | /* Can not reference other lanes yet */ 125 | refLane = position.lane; 126 | } 127 | return refLane; 128 | } 129 | 130 | private static int getRefColumn(Instance instance, Position position, long pseudoRandom, 131 | boolean sameLane) { 132 | 133 | int referenceAreaSize; 134 | int startPosition; 135 | 136 | if (position.pass == 0) { 137 | startPosition = 0; 138 | 139 | if (sameLane) { 140 | /* The same lane => add current segment */ 141 | referenceAreaSize = position.slice * instance.getSegmentLength() + position.index - 1; 142 | } else { 143 | /* pass == 0 && !sameLane => position.slice > 0*/ 144 | referenceAreaSize = position.slice * instance.getSegmentLength() + ((position.index == 0) ? (-1) : 0); 145 | } 146 | 147 | } else { 148 | startPosition = ((position.slice + 1) * instance.getSegmentLength()) % instance.getLaneLength(); 149 | 150 | if (sameLane) { 151 | referenceAreaSize = instance.getLaneLength() - instance.getSegmentLength() + position.index - 1; 152 | } else { 153 | referenceAreaSize = instance.getLaneLength() - instance.getSegmentLength() + ((position.index == 0) ? (-1) : 0); 154 | } 155 | } 156 | 157 | long relativePosition = pseudoRandom & 0xFFFFFFFFL; 158 | // long relativePosition = pseudoRandom << 32 >>> 32; 159 | relativePosition = (relativePosition * relativePosition) >>> 32; 160 | relativePosition = referenceAreaSize - 1 - (referenceAreaSize * relativePosition >>> 32); 161 | 162 | return (int) (startPosition + relativePosition) % instance.getLaneLength(); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/Finalize.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.Argon2; 4 | import at.gadermaier.argon2.model.Block; 5 | import at.gadermaier.argon2.model.Instance; 6 | 7 | public class Finalize { 8 | 9 | public static void finalize(Instance instance, Argon2 argon2) { 10 | 11 | Block finalBlock = instance.memory[instance.getLaneLength() - 1]; 12 | 13 | /* XOR the last blocks */ 14 | for (int i = 1; i < instance.getLanes(); i++) { 15 | int lastBlockInLane = i * instance.getLaneLength() + (instance.getLaneLength() - 1); 16 | finalBlock.xorWith(instance.memory[lastBlockInLane]); 17 | } 18 | 19 | byte[] finalBlockBytes = finalBlock.toBytes(); 20 | byte[] finalResult = Functions.blake2bLong(finalBlockBytes, argon2.getOutputLength()); 21 | 22 | argon2.setOutput(finalResult); 23 | 24 | if (argon2.isClearMemory()) { 25 | instance.clear(); 26 | argon2.clear(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/Functions.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.Util; 4 | import at.gadermaier.argon2.blake2.Blake2b; 5 | import at.gadermaier.argon2.model.Block; 6 | 7 | import static at.gadermaier.argon2.Constants.*; 8 | 9 | class Functions { 10 | 11 | 12 | /** 13 | * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X) 14 | * -> 64 byte (ARGON2_PREHASH_DIGEST_LENGTH) 15 | */ 16 | static byte[] initialHash(byte[] lanes, byte[] outputLength, 17 | byte[] memory, byte[] iterations, 18 | byte[] version, byte[] type, 19 | byte[] passwordLength, byte[] password, 20 | byte[] saltLength, byte[] salt, 21 | byte[] secretLength, byte[] secret, 22 | byte[] additionalLength, byte[] additional) { 23 | 24 | 25 | Blake2b.Param params = new Blake2b.Param() 26 | .setDigestLength(ARGON2_PREHASH_DIGEST_LENGTH); 27 | 28 | final Blake2b blake2b = Blake2b.Digest.newInstance(params); 29 | 30 | blake2b.update(lanes); 31 | blake2b.update(outputLength); 32 | blake2b.update(memory); 33 | blake2b.update(iterations); 34 | blake2b.update(version); 35 | blake2b.update(type); 36 | 37 | blake2b.update(passwordLength); 38 | if (password != null) { 39 | blake2b.update(password); 40 | } 41 | 42 | blake2b.update(saltLength); 43 | if (salt != null) { 44 | blake2b.update(salt); 45 | } 46 | 47 | blake2b.update(secretLength); 48 | if (secret != null) { 49 | blake2b.update(secret); 50 | } 51 | 52 | blake2b.update(additionalLength); 53 | if (additional != null) { 54 | blake2b.update(additional); 55 | } 56 | 57 | byte[] blake2hash = blake2b.digest(); 58 | assert (blake2hash.length == 64); 59 | 60 | return blake2hash; 61 | } 62 | 63 | 64 | /** 65 | * H' - blake2bLong - variable length hash function 66 | */ 67 | static byte[] blake2bLong(byte[] input, int outputLength) { 68 | 69 | assert (input.length == ARGON2_PREHASH_SEED_LENGTH || input.length == ARGON2_BLOCK_SIZE); 70 | 71 | byte[] result = new byte[outputLength]; 72 | byte[] outlenBytes = Util.intToLittleEndianBytes(outputLength); 73 | 74 | int blake2bLength = 64; 75 | 76 | if (outputLength <= blake2bLength) { 77 | result = blake2b(input, outlenBytes, outputLength); 78 | } else { 79 | byte[] outBuffer; 80 | 81 | /* V1 */ 82 | outBuffer = blake2b(input, outlenBytes, blake2bLength); 83 | System.arraycopy(outBuffer, 0, result, 0, blake2bLength / 2); 84 | 85 | int r = (outputLength / 32) + (outputLength % 32 == 0 ? 0 : 1) - 2; 86 | 87 | int position = blake2bLength / 2; 88 | for (int i = 2; i <= r; i++, position += blake2bLength / 2) { 89 | /* V2 to Vr */ 90 | outBuffer = blake2b(outBuffer, null, blake2bLength); 91 | System.arraycopy(outBuffer, 0, result, position, blake2bLength / 2); 92 | } 93 | 94 | int lastLength = outputLength - 32 * r; 95 | 96 | /* Vr+1 */ 97 | outBuffer = blake2b(outBuffer, null, lastLength); 98 | System.arraycopy(outBuffer, 0, result, position, lastLength); 99 | } 100 | 101 | assert (result.length == outputLength); 102 | return result; 103 | } 104 | 105 | private static byte[] blake2b(byte[] input, byte[] outlenBytes, int outputLength) { 106 | Blake2b.Param params = new Blake2b.Param() 107 | .setDigestLength(outputLength); 108 | 109 | final Blake2b blake2b = Blake2b.Digest.newInstance(params); 110 | 111 | if (outlenBytes != null) 112 | blake2b.update(outlenBytes); 113 | 114 | blake2b.update(input); 115 | 116 | return blake2b.digest(); 117 | } 118 | 119 | static void roundFunction(Block block, 120 | int v0, int v1, int v2, int v3, 121 | int v4, int v5, int v6, int v7, 122 | int v8, int v9, int v10, int v11, 123 | int v12, int v13, int v14, int v15) { 124 | 125 | F(block, v0, v4, v8, v12); 126 | F(block, v1, v5, v9, v13); 127 | F(block, v2, v6, v10, v14); 128 | F(block, v3, v7, v11, v15); 129 | 130 | F(block, v0, v5, v10, v15); 131 | F(block, v1, v6, v11, v12); 132 | F(block, v2, v7, v8, v13); 133 | F(block, v3, v4, v9, v14); 134 | } 135 | 136 | private static void F(Block block, int a, int b, int c, int d) { 137 | fBlaMka(block, a, b); 138 | rotr64(block, d, a, 32); 139 | 140 | fBlaMka(block, c, d); 141 | rotr64(block, b, c, 24); 142 | 143 | fBlaMka(block, a, b); 144 | rotr64(block, d, a, 16); 145 | 146 | fBlaMka(block, c, d); 147 | rotr64(block, b, c, 63); 148 | } 149 | 150 | /*designed by the Lyra PHC team */ 151 | /* a <- a + b + 2*aL*bL 152 | * + == addition modulo 2^64 153 | * aL = least 32 bit */ 154 | private static void fBlaMka(Block block, int x, int y) { 155 | final long m = 0xFFFFFFFFL; 156 | final long xy = (block.v[x] & m) * (block.v[y] & m); 157 | 158 | block.v[x] = block.v[x] + block.v[y] + 2 * xy; 159 | } 160 | 161 | private static void rotr64(Block block, int v, int w, long c) { 162 | final long temp = block.v[v] ^ block.v[w]; 163 | block.v[v] = (temp >>> c) | (temp << (64 - c)); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/algorithm/Initialize.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.algorithm; 2 | 3 | import at.gadermaier.argon2.Argon2; 4 | import at.gadermaier.argon2.Util; 5 | import at.gadermaier.argon2.model.Instance; 6 | 7 | import static at.gadermaier.argon2.Constants.*; 8 | 9 | public class Initialize { 10 | 11 | 12 | public static void initialize(Instance instance, Argon2 argon2) { 13 | byte[] initialHash = Functions.initialHash( 14 | Util.intToLittleEndianBytes(argon2.getLanes()), 15 | Util.intToLittleEndianBytes(argon2.getOutputLength()), 16 | Util.intToLittleEndianBytes(argon2.getMemory()), 17 | Util.intToLittleEndianBytes(argon2.getIterations()), 18 | Util.intToLittleEndianBytes(argon2.getVersion()), 19 | Util.intToLittleEndianBytes(argon2.getType().ordinal()), 20 | Util.intToLittleEndianBytes(argon2.getPasswordLength()), 21 | argon2.getPassword(), 22 | Util.intToLittleEndianBytes(argon2.getSaltLength()), 23 | argon2.getSalt(), 24 | Util.intToLittleEndianBytes(argon2.getSecretLength()), 25 | argon2.getSecret(), 26 | Util.intToLittleEndianBytes(argon2.getAdditionalLength()), 27 | argon2.getAdditional() 28 | ); 29 | fillFirstBlocks(instance, initialHash); 30 | } 31 | 32 | /** 33 | * (H0 || 0 || i) 72 byte -> 1024 byte 34 | * (H0 || 1 || i) 72 byte -> 1024 byte 35 | */ 36 | private static void fillFirstBlocks(Instance instance, byte[] initialHash) { 37 | 38 | final byte[] zeroBytes = {0, 0, 0, 0}; 39 | final byte[] oneBytes = {1, 0, 0, 0}; 40 | 41 | byte[] initialHashWithZeros = getInitialHashLong(initialHash, zeroBytes); 42 | byte[] initialHashWithOnes = getInitialHashLong(initialHash, oneBytes); 43 | 44 | for (int i = 0; i < instance.getLanes(); i++) { 45 | 46 | byte[] iBytes = Util.intToLittleEndianBytes(i); 47 | 48 | System.arraycopy(iBytes, 0, initialHashWithZeros, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); 49 | System.arraycopy(iBytes, 0, initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4, 4); 50 | 51 | byte[] blockhashBytes = Functions.blake2bLong(initialHashWithZeros, ARGON2_BLOCK_SIZE); 52 | instance.memory[i * instance.getLaneLength() + 0].fromBytes(blockhashBytes); 53 | 54 | blockhashBytes = Functions.blake2bLong(initialHashWithOnes, ARGON2_BLOCK_SIZE); 55 | instance.memory[i * instance.getLaneLength() + 1].fromBytes(blockhashBytes); 56 | } 57 | } 58 | 59 | private static byte[] getInitialHashLong(byte[] initialHash, byte[] appendix) { 60 | byte[] initialHashLong = new byte[ARGON2_PREHASH_SEED_LENGTH]; 61 | 62 | System.arraycopy(initialHash, 0, initialHashLong, 0, ARGON2_PREHASH_DIGEST_LENGTH); 63 | System.arraycopy(appendix, 0, initialHashLong, ARGON2_PREHASH_DIGEST_LENGTH, 4); 64 | 65 | return initialHashLong; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/blake2/Blake2b.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* This file is taken from 4 | https://github.com/alphazero/Blake2b/ 5 | 6 | I included just the file for the sake of simplicity 7 | because the repository artifact was not uploaded to maven central repository 8 | 9 | */ 10 | /* 11 | A Java implementation of BLAKE2B cryptographic digest algorithm. 12 | 13 | Joubin Mohammad Houshyar 14 | bushwick, nyc 15 | 02-14-2014 16 | 17 | -- 18 | 19 | To the extent possible under law, the author(s) have dedicated all copyright 20 | and related and neighboring rights to this software to the public domain 21 | worldwide. This software is distributed without any warranty. 22 | 23 | You should have received a copy of the CC0 Public Domain Dedication along with 24 | this software. If not, see . 25 | */ 26 | 27 | package at.gadermaier.argon2.blake2; 28 | 29 | 30 | import java.io.PrintStream; 31 | import java.security.Key; 32 | import java.security.spec.AlgorithmParameterSpec; 33 | import java.util.Arrays; 34 | 35 | import static at.gadermaier.argon2.blake2.Blake2b.Engine.Assert.*; 36 | import static at.gadermaier.argon2.blake2.Blake2b.Engine.LittleEndian.*; 37 | 38 | 39 | /** */ 40 | public interface Blake2b { 41 | /** */ 42 | void update(byte[] input); 43 | 44 | // --------------------------------------------------------------------- 45 | // API 46 | // --------------------------------------------------------------------- 47 | // TODO add ByteBuffer variants 48 | 49 | /** */ 50 | void update(byte input); 51 | 52 | /** */ 53 | void update(byte[] input, int offset, int len); 54 | 55 | /** */ 56 | byte[] digest(); 57 | 58 | /** */ 59 | byte[] digest(byte[] input); 60 | 61 | /** */ 62 | void digest(byte[] output, int offset, int len); 63 | 64 | /** */ 65 | void reset(); 66 | 67 | // --------------------------------------------------------------------- 68 | // Specification 69 | // --------------------------------------------------------------------- 70 | public interface Spec { 71 | /** pblock size of blake2b */ 72 | int param_bytes = 64; 73 | 74 | /** pblock size of blake2b */ 75 | int block_bytes = 128; 76 | 77 | /** maximum digest size */ 78 | int max_digest_bytes = 64; 79 | 80 | /** maximum key sie */ 81 | int max_key_bytes = 64; 82 | 83 | /** maximum salt size */ 84 | int max_salt_bytes = 16; 85 | 86 | /** maximum personalization string size */ 87 | int max_personalization_bytes = 16; 88 | 89 | /** length of h space vector array */ 90 | int state_space_len = 8; 91 | 92 | /** max tree fanout value */ 93 | int max_tree_fantout = 0xFF; 94 | 95 | /** max tree depth value */ 96 | int max_tree_depth = 0xFF; 97 | 98 | /** max tree leaf length value.Note that this has uint32 semantics 99 | and thus 0xFFFFFFFF is used as max value limit. */ 100 | int max_tree_leaf_length = 0xFFFFFFFF; 101 | 102 | /** max node offset value. Note that this has uint64 semantics 103 | and thus 0xFFFFFFFFFFFFFFFFL is used as max value limit. */ 104 | long max_node_offset = 0xFFFFFFFFFFFFFFFFL; 105 | 106 | /** max tree inner length value */ 107 | int max_tree_inner_length = 0xFF; 108 | 109 | /** initialization values map ref-Spec IV[i] -> slice iv[i*8:i*8+7] */ 110 | long[] IV = { 111 | 0x6a09e667f3bcc908L, 112 | 0xbb67ae8584caa73bL, 113 | 0x3c6ef372fe94f82bL, 114 | 0xa54ff53a5f1d36f1L, 115 | 0x510e527fade682d1L, 116 | 0x9b05688c2b3e6c1fL, 117 | 0x1f83d9abfb41bd6bL, 118 | 0x5be0cd19137e2179L 119 | }; 120 | 121 | /** sigma per spec used in compress func generation - for reference only */ 122 | static byte[][] sigma = { 123 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , 124 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , 125 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , 126 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , 127 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , 128 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , 129 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , 130 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , 131 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , 132 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , 133 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , 134 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } 135 | }; 136 | } 137 | 138 | // --------------------------------------------------------------------- 139 | // Blake2b Message Digest 140 | // --------------------------------------------------------------------- 141 | 142 | /** Generalized Blake2b digest. */ 143 | public static class Digest extends Engine implements Blake2b { 144 | private Digest (final Param p) { super (p); } 145 | private Digest () { super (); } 146 | 147 | public static Digest newInstance () { 148 | return new Digest (); 149 | } 150 | public static Digest newInstance (final int digestLength) { 151 | return new Digest (new Param().setDigestLength(digestLength)); 152 | } 153 | public static Digest newInstance (Param p) { 154 | return new Digest (p); 155 | } 156 | } 157 | 158 | // --------------------------------------------------------------------- 159 | // Blake2b Message Authentication Code 160 | // --------------------------------------------------------------------- 161 | 162 | /** Message Authentication Code (MAC) digest. */ 163 | public static class Mac extends Engine implements Blake2b { 164 | private Mac (final Param p) { super (p); } 165 | private Mac () { super (); } 166 | 167 | /** Blake2b.MAC 512 - using default Blake2b.Spec settings with given key */ 168 | public static Mac newInstance (final byte[] key) { 169 | return new Mac (new Param().setKey(key)); 170 | } 171 | /** Blake2b.MAC - using default Blake2b.Spec settings with given key, with given digest length */ 172 | public static Mac newInstance (final byte[] key, final int digestLength) { 173 | return new Mac (new Param().setKey(key).setDigestLength(digestLength)); 174 | } 175 | /** Blake2b.MAC - using default Blake2b.Spec settings with given java.security.Key, with given digest length */ 176 | public static Mac newInstance (final Key key, final int digestLength) { 177 | return new Mac (new Param().setKey(key).setDigestLength(digestLength)); 178 | } 179 | /** Blake2b.MAC - using the specified Parameters. 180 | * @param p asserted valid configured Param with key */ 181 | public static Mac newInstance (Param p) { 182 | assert p != null : "Param (p) is null"; 183 | assert p.hasKey() : "Param (p) not configured with a key"; 184 | return new Mac (p); 185 | } 186 | } 187 | 188 | // --------------------------------------------------------------------- 189 | // Blake2b Incremental Message Digest (Tree) 190 | // --------------------------------------------------------------------- 191 | 192 | /** 193 | * Note that Tree is just a convenience class; incremental hash (tree) 194 | * can be done directly with the Digest class. 195 | *
196 | * Further node, that tree does NOT accumulate the leaf hashes -- 197 | * you need to do that 198 | */ 199 | public static class Tree { 200 | 201 | final int depth; 202 | final int fanout; 203 | final int leaf_length; 204 | final int inner_length; 205 | final int digest_length; 206 | 207 | /** 208 | * 209 | * @param fanout 210 | * @param depth 211 | * @param leaf_length size of data input for leaf nodes. 212 | * @param inner_length note this is used also as digest-length for non-root nodes. 213 | * @param digest_length final hash out digest-length for the tree 214 | */ 215 | public Tree ( 216 | final int depth, 217 | final int fanout, 218 | final int leaf_length, 219 | final int inner_length, 220 | final int digest_length 221 | ) { 222 | this.fanout = fanout; 223 | this.depth = depth; 224 | this.leaf_length = leaf_length; 225 | this.inner_length = inner_length; 226 | this.digest_length = digest_length; 227 | } 228 | private Param treeParam() { 229 | return new Param(). 230 | setDepth(depth).setFanout(fanout).setLeafLength(leaf_length).setInnerLength(inner_length); 231 | } 232 | /** returns the Digest for tree node @ (depth, offset) */ 233 | public final Digest getNode (final int depth, final int offset) { 234 | final Param nodeParam = treeParam().setNodeDepth(depth).setNodeOffset(offset).setDigestLength(inner_length); 235 | return Digest.newInstance(nodeParam); 236 | } 237 | /** returns the Digest for root node */ 238 | public final Digest getRoot () { 239 | final int depth = this.depth - 1; 240 | final Param rootParam = treeParam().setNodeDepth(depth).setNodeOffset(0L).setDigestLength(digest_length); 241 | return Digest.newInstance(rootParam); 242 | } 243 | } 244 | 245 | // --------------------------------------------------------------------- 246 | // Engine 247 | // --------------------------------------------------------------------- 248 | static class Engine implements Blake2b { 249 | 250 | /* G0 sigmas */ 251 | static final int[] sig_g00 = { 0, 14, 11, 7, 9, 2, 12, 13, 6, 10, 0, 14, }; 252 | static final int[] sig_g01 = { 1, 10, 8, 9, 0, 12, 5, 11, 15, 2, 1, 10, }; 253 | 254 | /* G1 sigmas */ 255 | static final int[] sig_g10 = { 2, 4, 12, 3, 5, 6, 1, 7, 14, 8, 2, 4, }; 256 | static final int[] sig_g11 = { 3, 8, 0, 1, 7, 10, 15, 14, 9, 4, 3, 8, }; 257 | 258 | /* G2 sigmas */ 259 | static final int[] sig_g20 = { 4, 9, 5, 13, 2, 0, 14, 12, 11, 7, 4, 9, }; 260 | static final int[] sig_g21 = { 5, 15, 2, 12, 4, 11, 13, 1, 3, 6, 5, 15, }; 261 | 262 | /* G3 sigmas */ 263 | static final int[] sig_g30 = { 6, 13, 15, 11, 10, 8, 4, 3, 0, 1, 6, 13, }; 264 | static final int[] sig_g31 = { 7, 6, 13, 14, 15, 3, 10, 9, 8, 5, 7, 6, }; 265 | 266 | /* G4 sigmas */ 267 | static final int[] sig_g40 = { 8, 1, 10, 2, 14, 4, 0, 5, 12, 15, 8, 1, }; 268 | static final int[] sig_g41 = { 9, 12, 14, 6, 1, 13, 7, 0, 2, 11, 9, 12, }; 269 | 270 | /* G5 sigmas */ 271 | static final int[] sig_g50 = { 10, 0, 3, 5, 11, 7, 6, 15, 13, 9, 10, 0, }; 272 | static final int[] sig_g51 = { 11, 2, 6, 10, 12, 5, 3, 4, 7, 14, 11, 2, }; 273 | 274 | /* G6 sigmas */ 275 | static final int[] sig_g60 = { 12, 11, 7, 4, 6, 15, 9, 8, 1, 3, 12, 11, }; 276 | static final int[] sig_g61 = { 13, 7, 1, 0, 8, 14, 2, 6, 4, 12, 13, 7, }; 277 | 278 | /* G7 sigmas */ 279 | static final int[] sig_g70 = { 14, 5, 9, 15, 3, 1, 8, 2, 10, 13, 14, 5, }; 280 | static final int[] sig_g71 = { 15, 3, 4, 8, 13, 9, 11, 10, 5, 0, 15, 3, }; 281 | 282 | // --------------------------------------------------------------------- 283 | // Blake2b State(+) per reference implementation 284 | // --------------------------------------------------------------------- 285 | // REVU: address last_node TODO part of the Tree/incremental 286 | /** 287 | * read only 288 | */ 289 | private static byte[] zeropad = new byte[Spec.block_bytes]; 290 | /** 291 | * per spec 292 | */ 293 | private final long[] h = new long [ 8 ]; 294 | /** per spec */ 295 | private final long[] t = new long [ 2 ]; 296 | /** per spec */ 297 | private final long[] f = new long [ 2 ]; 298 | /** pulled up 2b optimal */ 299 | private final long[] m = new long [16]; 300 | /** pulled up 2b optimal */ 301 | private final long[] v = new long [16]; 302 | 303 | /** compressor cache buffer */ 304 | private final byte[] buffer; 305 | /** configuration params */ 306 | private final Param param; 307 | /** digest length from init param - copied here on init */ 308 | private final int outlen; 309 | /** 310 | * per spec (tree) 311 | */ 312 | private boolean last_node = false; 313 | /** 314 | * compressor cache buffer offset/cached data length 315 | */ 316 | private int buflen; 317 | /** to support update(byte) */ 318 | private byte[] oneByte; 319 | 320 | /** Basic use constructor pending (TODO) JCA/JCE compliance */ 321 | Engine() { 322 | this(new Param()); 323 | } 324 | 325 | // --------------------------------------------------------------------- 326 | // Ctor & Initialization 327 | // --------------------------------------------------------------------- 328 | 329 | /** User provided Param for custom configurations */ 330 | Engine(final Param param) { 331 | assert param != null : "param is null"; 332 | this.param = param; 333 | this.buffer = new byte[Spec.block_bytes]; 334 | this.oneByte = new byte[1]; 335 | this.outlen = param.getDigestLength(); 336 | 337 | if (param.getDepth() > Param.Default.depth) { 338 | final int ndepth = param.getNodeDepth(); 339 | final long nxoff = param.getNodeOffset(); 340 | if (ndepth == param.getDepth() - 1) { 341 | last_node = true; 342 | assert param.getNodeOffset() == 0 : "root must have offset of zero"; 343 | } else if (param.getNodeOffset() == param.getFanout() - 1) { 344 | this.last_node = true; 345 | } 346 | } 347 | 348 | initialize(); 349 | 350 | // Debug.dumpBuffer(System.out, "param bytes at init", param.getBytes()); 351 | 352 | } 353 | 354 | public static void main(String... args) { 355 | Blake2b mac = Blake2b.Mac.newInstance("LOVE".getBytes()); 356 | final byte[] hash = mac.digest("Salaam!".getBytes()); 357 | // Debug.dumpBuffer(System.out, "-- mac hash --", hash); 358 | } 359 | 360 | private void initialize () { 361 | // state vector h - copy values to address reset() requests 362 | System.arraycopy( param.initialized_H(), 0, this.h, 0, Spec.state_space_len); 363 | 364 | // Debug.dumpArray("init H", this.h); 365 | // if we have a key update initial block 366 | // Note param has zero padded key_bytes to Spec.max_key_bytes 367 | if(param.hasKey){ 368 | this.update (param.key_bytes, 0, Spec.block_bytes); 369 | } 370 | } 371 | 372 | /** 373 | * {@inheritDoc} 374 | */ 375 | @Override 376 | final public void reset() { 377 | // reset cache 378 | this.buflen = 0; 379 | for (int i = 0; i < buffer.length; i++) { 380 | buffer[i] = (byte) 0; 381 | } 382 | 383 | // reset flags 384 | this.f[0] = 0L; 385 | this.f[1] = 0L; 386 | 387 | // reset counters 388 | this.t[0] = 0L; 389 | this.t[1] = 0L; 390 | 391 | // reset state vector 392 | // NOTE: keep as last stmt as init calls update0 for MACs. 393 | initialize(); 394 | } 395 | 396 | // --------------------------------------------------------------------- 397 | // interface: Blake2b API 398 | // --------------------------------------------------------------------- 399 | 400 | /** {@inheritDoc} */ 401 | @Override final public void update (final byte[] b, int off, int len) { 402 | if (b == null) { 403 | throw new IllegalArgumentException("input buffer (b) is null"); 404 | } 405 | /* zero or more calls to compress */ 406 | // REVU: possibly the double buffering of c-ref is more sensible .. 407 | // regardless, the hotspot is in the compress, as expected. 408 | while (len > 0) { 409 | if ( buflen == 0) { 410 | /* try compressing direct from input ? */ 411 | while ( len > Spec.block_bytes ) { 412 | this.t[0] += Spec.block_bytes; 413 | this.t[1] += this.t[0] == 0 ? 1 : 0; 414 | compress( b, off); 415 | len -= Spec.block_bytes; 416 | off += Spec.block_bytes; 417 | } 418 | } else if ( buflen == Spec.block_bytes ) { 419 | /* flush */ 420 | this.t[0] += Spec.block_bytes; 421 | this.t[1] += this.t[0] == 0 ? 1 : 0; 422 | compress( buffer, 0 ); 423 | buflen = 0; 424 | continue; 425 | } 426 | 427 | // "are we there yet?" 428 | if( len == 0 ) return; 429 | 430 | final int cap = Spec.block_bytes - buflen; 431 | final int fill = len > cap ? cap : len; 432 | System.arraycopy( b, off, buffer, buflen, fill ); 433 | buflen += fill; 434 | len -= fill; 435 | off += fill; 436 | } 437 | } 438 | 439 | /** {@inheritDoc} */ 440 | @Override final public void update (byte b) { 441 | oneByte[0] = b; 442 | update (oneByte, 0, 1); 443 | } 444 | 445 | /** {@inheritDoc} */ 446 | @Override final public void update(byte[] input) { 447 | update (input, 0, input.length); 448 | } 449 | 450 | /** {@inheritDoc} */ 451 | @Override final public void digest(byte[] output, int off, int len) { 452 | // zero pad last block; set last block flags; and compress 453 | System.arraycopy( zeropad, 0, buffer, buflen, Spec.block_bytes - buflen); 454 | if(buflen > 0) { 455 | this.t[0] += buflen; 456 | this.t[1] += this.t[0] == 0 ? 1 : 0; 457 | } 458 | 459 | this.f[ flag.last_block ] = 0xFFFFFFFFFFFFFFFFL; 460 | this.f[ flag.last_node ] = this.last_node ? 0xFFFFFFFFFFFFFFFFL : 0x0L; 461 | 462 | // compres and write final out (truncated to len) to output 463 | compress( buffer, 0 ); 464 | hashout( output, off, len ); 465 | 466 | reset(); 467 | } 468 | 469 | /** {@inheritDoc} */ 470 | @Override final public byte[] digest () throws IllegalArgumentException { 471 | final byte[] out = new byte [outlen]; 472 | digest ( out, 0, outlen ); 473 | return out; 474 | } 475 | 476 | /** {@inheritDoc} */ 477 | @Override final public byte[] digest (byte[] input) { 478 | update(input, 0, input.length); 479 | return digest(); 480 | } 481 | 482 | /** 483 | * write out the digest output from the 'h' registers. 484 | * truncate full output if necessary. 485 | */ 486 | private void hashout (final byte[] out, final int offset, final int hashlen) { 487 | // write max number of whole longs 488 | final int lcnt = hashlen >>> 3; 489 | long v = 0; 490 | int i = offset; 491 | for (int w = 0; w < lcnt; w++) { 492 | v = h [ w ]; 493 | out [ i++ ] = (byte) v; v >>>= 8; 494 | out [ i++ ] = (byte) v; v >>>= 8; 495 | out [ i++ ] = (byte) v; v >>>= 8; 496 | out [ i++ ] = (byte) v; v >>>= 8; 497 | out [ i++ ] = (byte) v; v >>>= 8; 498 | out [ i++ ] = (byte) v; v >>>= 8; 499 | out [ i++ ] = (byte) v; v >>>= 8; 500 | out [ i++ ] = (byte) v; 501 | } 502 | 503 | // basta? 504 | if( hashlen == Spec.max_digest_bytes) return; 505 | 506 | // write the remaining bytes of a partial long value 507 | v = h[lcnt]; 508 | i = lcnt << 3; 509 | while (i < hashlen) { 510 | out[offset + i] = (byte) v; 511 | v >>>= 8; 512 | ++i; 513 | } 514 | } 515 | 516 | // --------------------------------------------------------------------- 517 | // Internal Ops 518 | // --------------------------------------------------------------------- 519 | 520 | /** compress Spec.block_bytes data from b, from offset */ 521 | private void compress(final byte[] b, final int offset) { 522 | 523 | // set m registers 524 | // REVU: some small gains still possible here. 525 | m[0] = ((long) b[offset] & 0xFF); 526 | m[0] |= ((long) b[offset + 1] & 0xFF) << 8; 527 | m[0] |= ((long) b[offset + 2] & 0xFF) << 16; 528 | m[0] |= ((long) b[offset + 3] & 0xFF) << 24; 529 | m[0] |= ((long) b[offset + 4] & 0xFF) << 32; 530 | m[0] |= ((long) b[offset + 5] & 0xFF) << 40; 531 | m[0] |= ((long) b[offset + 6] & 0xFF) << 48; 532 | m[0] |= ((long) b[offset + 7]) << 56; 533 | 534 | m[1] = ((long) b[offset + 8] & 0xFF); 535 | m[1] |= ((long) b[offset + 9] & 0xFF) << 8; 536 | m[1] |= ((long) b[offset + 10] & 0xFF) << 16; 537 | m[1] |= ((long) b[offset + 11] & 0xFF) << 24; 538 | m[1] |= ((long) b[offset + 12] & 0xFF) << 32; 539 | m[1] |= ((long) b[offset + 13] & 0xFF) << 40; 540 | m[1] |= ((long) b[offset + 14] & 0xFF) << 48; 541 | m[1] |= ((long) b[offset + 15]) << 56; 542 | 543 | m[2] = ((long) b[offset + 16] & 0xFF); 544 | m[2] |= ((long) b[offset + 17] & 0xFF) << 8; 545 | m[2] |= ((long) b[offset + 18] & 0xFF) << 16; 546 | m[2] |= ((long) b[offset + 19] & 0xFF) << 24; 547 | m[2] |= ((long) b[offset + 20] & 0xFF) << 32; 548 | m[2] |= ((long) b[offset + 21] & 0xFF) << 40; 549 | m[2] |= ((long) b[offset + 22] & 0xFF) << 48; 550 | m[2] |= ((long) b[offset + 23]) << 56; 551 | 552 | m[3] = ((long) b[offset + 24] & 0xFF); 553 | m[3] |= ((long) b[offset + 25] & 0xFF) << 8; 554 | m[3] |= ((long) b[offset + 26] & 0xFF) << 16; 555 | m[3] |= ((long) b[offset + 27] & 0xFF) << 24; 556 | m[3] |= ((long) b[offset + 28] & 0xFF) << 32; 557 | m[3] |= ((long) b[offset + 29] & 0xFF) << 40; 558 | m[3] |= ((long) b[offset + 30] & 0xFF) << 48; 559 | m[3] |= ((long) b[offset + 31]) << 56; 560 | 561 | m[4] = ((long) b[offset + 32] & 0xFF); 562 | m[4] |= ((long) b[offset + 33] & 0xFF) << 8; 563 | m[4] |= ((long) b[offset + 34] & 0xFF) << 16; 564 | m[4] |= ((long) b[offset + 35] & 0xFF) << 24; 565 | m[4] |= ((long) b[offset + 36] & 0xFF) << 32; 566 | m[4] |= ((long) b[offset + 37] & 0xFF) << 40; 567 | m[4] |= ((long) b[offset + 38] & 0xFF) << 48; 568 | m[4] |= ((long) b[offset + 39]) << 56; 569 | 570 | m[5] = ((long) b[offset + 40] & 0xFF); 571 | m[5] |= ((long) b[offset + 41] & 0xFF) << 8; 572 | m[5] |= ((long) b[offset + 42] & 0xFF) << 16; 573 | m[5] |= ((long) b[offset + 43] & 0xFF) << 24; 574 | m[5] |= ((long) b[offset + 44] & 0xFF) << 32; 575 | m[5] |= ((long) b[offset + 45] & 0xFF) << 40; 576 | m[5] |= ((long) b[offset + 46] & 0xFF) << 48; 577 | m[5] |= ((long) b[offset + 47]) << 56; 578 | 579 | m[6] = ((long) b[offset + 48] & 0xFF); 580 | m[6] |= ((long) b[offset + 49] & 0xFF) << 8; 581 | m[6] |= ((long) b[offset + 50] & 0xFF) << 16; 582 | m[6] |= ((long) b[offset + 51] & 0xFF) << 24; 583 | m[6] |= ((long) b[offset + 52] & 0xFF) << 32; 584 | m[6] |= ((long) b[offset + 53] & 0xFF) << 40; 585 | m[6] |= ((long) b[offset + 54] & 0xFF) << 48; 586 | m[6] |= ((long) b[offset + 55]) << 56; 587 | 588 | m[7] = ((long) b[offset + 56] & 0xFF); 589 | m[7] |= ((long) b[offset + 57] & 0xFF) << 8; 590 | m[7] |= ((long) b[offset + 58] & 0xFF) << 16; 591 | m[7] |= ((long) b[offset + 59] & 0xFF) << 24; 592 | m[7] |= ((long) b[offset + 60] & 0xFF) << 32; 593 | m[7] |= ((long) b[offset + 61] & 0xFF) << 40; 594 | m[7] |= ((long) b[offset + 62] & 0xFF) << 48; 595 | m[7] |= ((long) b[offset + 63]) << 56; 596 | 597 | m[8] = ((long) b[offset + 64] & 0xFF); 598 | m[8] |= ((long) b[offset + 65] & 0xFF) << 8; 599 | m[8] |= ((long) b[offset + 66] & 0xFF) << 16; 600 | m[8] |= ((long) b[offset + 67] & 0xFF) << 24; 601 | m[8] |= ((long) b[offset + 68] & 0xFF) << 32; 602 | m[8] |= ((long) b[offset + 69] & 0xFF) << 40; 603 | m[8] |= ((long) b[offset + 70] & 0xFF) << 48; 604 | m[8] |= ((long) b[offset + 71]) << 56; 605 | 606 | m[9] = ((long) b[offset + 72] & 0xFF); 607 | m[9] |= ((long) b[offset + 73] & 0xFF) << 8; 608 | m[9] |= ((long) b[offset + 74] & 0xFF) << 16; 609 | m[9] |= ((long) b[offset + 75] & 0xFF) << 24; 610 | m[9] |= ((long) b[offset + 76] & 0xFF) << 32; 611 | m[9] |= ((long) b[offset + 77] & 0xFF) << 40; 612 | m[9] |= ((long) b[offset + 78] & 0xFF) << 48; 613 | m[9] |= ((long) b[offset + 79]) << 56; 614 | 615 | m[10] = ((long) b[offset + 80] & 0xFF); 616 | m[10] |= ((long) b[offset + 81] & 0xFF) << 8; 617 | m[10] |= ((long) b[offset + 82] & 0xFF) << 16; 618 | m[10] |= ((long) b[offset + 83] & 0xFF) << 24; 619 | m[10] |= ((long) b[offset + 84] & 0xFF) << 32; 620 | m[10] |= ((long) b[offset + 85] & 0xFF) << 40; 621 | m[10] |= ((long) b[offset + 86] & 0xFF) << 48; 622 | m[10] |= ((long) b[offset + 87]) << 56; 623 | 624 | m[11] = ((long) b[offset + 88] & 0xFF); 625 | m[11] |= ((long) b[offset + 89] & 0xFF) << 8; 626 | m[11] |= ((long) b[offset + 90] & 0xFF) << 16; 627 | m[11] |= ((long) b[offset + 91] & 0xFF) << 24; 628 | m[11] |= ((long) b[offset + 92] & 0xFF) << 32; 629 | m[11] |= ((long) b[offset + 93] & 0xFF) << 40; 630 | m[11] |= ((long) b[offset + 94] & 0xFF) << 48; 631 | m[11] |= ((long) b[offset + 95]) << 56; 632 | 633 | m[12] = ((long) b[offset + 96] & 0xFF); 634 | m[12] |= ((long) b[offset + 97] & 0xFF) << 8; 635 | m[12] |= ((long) b[offset + 98] & 0xFF) << 16; 636 | m[12] |= ((long) b[offset + 99] & 0xFF) << 24; 637 | m[12] |= ((long) b[offset + 100] & 0xFF) << 32; 638 | m[12] |= ((long) b[offset + 101] & 0xFF) << 40; 639 | m[12] |= ((long) b[offset + 102] & 0xFF) << 48; 640 | m[12] |= ((long) b[offset + 103]) << 56; 641 | 642 | m[13] = ((long) b[offset + 104] & 0xFF); 643 | m[13] |= ((long) b[offset + 105] & 0xFF) << 8; 644 | m[13] |= ((long) b[offset + 106] & 0xFF) << 16; 645 | m[13] |= ((long) b[offset + 107] & 0xFF) << 24; 646 | m[13] |= ((long) b[offset + 108] & 0xFF) << 32; 647 | m[13] |= ((long) b[offset + 109] & 0xFF) << 40; 648 | m[13] |= ((long) b[offset + 110] & 0xFF) << 48; 649 | m[13] |= ((long) b[offset + 111]) << 56; 650 | 651 | m[14] = ((long) b[offset + 112] & 0xFF); 652 | m[14] |= ((long) b[offset + 113] & 0xFF) << 8; 653 | m[14] |= ((long) b[offset + 114] & 0xFF) << 16; 654 | m[14] |= ((long) b[offset + 115] & 0xFF) << 24; 655 | m[14] |= ((long) b[offset + 116] & 0xFF) << 32; 656 | m[14] |= ((long) b[offset + 117] & 0xFF) << 40; 657 | m[14] |= ((long) b[offset + 118] & 0xFF) << 48; 658 | m[14] |= ((long) b[offset + 119]) << 56; 659 | 660 | m[15] = ((long) b[offset + 120] & 0xFF); 661 | m[15] |= ((long) b[offset + 121] & 0xFF) << 8; 662 | m[15] |= ((long) b[offset + 122] & 0xFF) << 16; 663 | m[15] |= ((long) b[offset + 123] & 0xFF) << 24; 664 | m[15] |= ((long) b[offset + 124] & 0xFF) << 32; 665 | m[15] |= ((long) b[offset + 125] & 0xFF) << 40; 666 | m[15] |= ((long) b[offset + 126] & 0xFF) << 48; 667 | m[15] |= ((long) b[offset + 127 ] ) << 56; 668 | // Debug.dumpArray("m @ compress", m); 669 | // 670 | // Debug.dumpArray("h @ compress", h); 671 | // Debug.dumpArray("t @ compress", t); 672 | // Debug.dumpArray("f @ compress", f); 673 | 674 | // set v registers 675 | v[0] = h[0]; 676 | v[1] = h[1]; 677 | v[2] = h[2]; 678 | v[3] = h[3]; 679 | v[4] = h[4]; 680 | v[5] = h[5]; 681 | v[6] = h[6]; 682 | v[7] = h[7]; 683 | v[8] = 0x6a09e667f3bcc908L; 684 | v[9] = 0xbb67ae8584caa73bL; 685 | v[10] = 0x3c6ef372fe94f82bL; 686 | v[11] = 0xa54ff53a5f1d36f1L; 687 | v[12] = t[0] ^ 0x510e527fade682d1L; 688 | v[13] = t[1] ^ 0x9b05688c2b3e6c1fL; 689 | v[14] = f[0] ^ 0x1f83d9abfb41bd6bL; 690 | v[15] = f[1] ^ 0x5be0cd19137e2179L; 691 | 692 | // Debug.dumpArray("v @ compress", v); 693 | // the rounds 694 | // REVU: let's try unrolling this again TODO do & bench 695 | for (int r = 0; r < 12; r++) { 696 | 697 | /** G (r, 0, 0, 4, 8, 12); */ 698 | 699 | v[0] = v[0] + v[4] + m[sig_g00[r]]; 700 | v[12] ^= v[0]; 701 | v[12] = (v[12] << 32) | (v[12] >>> 32); 702 | v[8] = v[8] + v[12]; 703 | v[4] ^= v[8]; 704 | v[4] = (v[4] >>> 24) | (v[4] << 40); 705 | v[0] = v[0] + v[4] + m[sig_g01[r]]; 706 | v[12] ^= v[0]; 707 | v[12] = (v[12] >>> 16) | (v[12] << 48); 708 | v[8] = v[8] + v[12]; 709 | v[4] ^= v[8]; 710 | v[4] = (v[4] << 1) | (v[4] >>> 63); 711 | 712 | /** G (r, 1, 1, 5, 9, 13); */ 713 | 714 | v[1] = v[1] + v[5] + m[sig_g10[r]]; 715 | v[13] ^= v[1]; 716 | v[13] = (v[13] << 32) | (v[13] >>> 32); 717 | v[9] = v[9] + v[13]; 718 | v[5] ^= v[9]; 719 | v[5] = (v[5] >>> 24) | (v[5] << 40); 720 | v[1] = v[1] + v[5] + m[sig_g11[r]]; 721 | v[13] ^= v[1]; 722 | v[13] = (v[13] >>> 16) | (v[13] << 48); 723 | v[9] = v[9] + v[13]; 724 | v[5] ^= v[9]; 725 | v[5] = (v[5] << 1) | (v[5] >>> 63); 726 | 727 | /** G (r, 2, 2, 6, 10, 14); */ 728 | 729 | v[2] = v[2] + v[6] + m[sig_g20[r]]; 730 | v[14] ^= v[2]; 731 | v[14] = (v[14] << 32) | (v[14] >>> 32); 732 | v[10] = v[10] + v[14]; 733 | v[6] ^= v[10]; 734 | v[6] = (v[6] >>> 24) | (v[6] << 40); 735 | v[2] = v[2] + v[6] + m[sig_g21[r]]; 736 | v[14] ^= v[2]; 737 | v[14] = (v[14] >>> 16) | (v[14] << 48); 738 | v[10] = v[10] + v[14]; 739 | v[6] ^= v[10]; 740 | v[6] = (v[6] << 1) | (v[6] >>> 63); 741 | 742 | /** G (r, 3, 3, 7, 11, 15); */ 743 | 744 | v[3] = v[3] + v[7] + m[sig_g30[r]]; 745 | v[15] ^= v[3]; 746 | v[15] = (v[15] << 32) | (v[15] >>> 32); 747 | v[11] = v[11] + v[15]; 748 | v[7] ^= v[11]; 749 | v[7] = (v[7] >>> 24) | (v[7] << 40); 750 | v[3] = v[3] + v[7] + m[sig_g31[r]]; 751 | v[15] ^= v[3]; 752 | v[15] = (v[15] >>> 16) | (v[15] << 48); 753 | v[11] = v[11] + v[15]; 754 | v[7] ^= v[11]; 755 | v[7] = (v[7] << 1) | (v[7] >>> 63); 756 | 757 | /** G (r, 4, 0, 5, 10, 15); */ 758 | 759 | v[0] = v[0] + v[5] + m[sig_g40[r]]; 760 | v[15] ^= v[0]; 761 | v[15] = (v[15] << 32) | (v[15] >>> 32); 762 | v[10] = v[10] + v[15]; 763 | v[5] ^= v[10]; 764 | v[5] = (v[5] >>> 24) | (v[5] << 40); 765 | v[0] = v[0] + v[5] + m[sig_g41[r]]; 766 | v[15] ^= v[0]; 767 | v[15] = (v[15] >>> 16) | (v[15] << 48); 768 | v[10] = v[10] + v[15]; 769 | v[5] ^= v[10]; 770 | v[5] = (v[5] << 1) | (v[5] >>> 63); 771 | 772 | /** G (r, 5, 1, 6, 11, 12); */ 773 | 774 | v[1] = v[1] + v[6] + m[sig_g50[r]]; 775 | v[12] ^= v[1]; 776 | v[12] = (v[12] << 32) | (v[12] >>> 32); 777 | v[11] = v[11] + v[12]; 778 | v[6] ^= v[11]; 779 | v[6] = (v[6] >>> 24) | (v[6] << 40); 780 | v[1] = v[1] + v[6] + +m[sig_g51[r]]; 781 | v[12] ^= v[1]; 782 | v[12] = (v[12] >>> 16) | (v[12] << 48); 783 | v[11] = v[11] + v[12]; 784 | v[6] ^= v[11]; 785 | v[6] = (v[6] << 1) | (v[6] >>> 63); 786 | 787 | /** G (r, 6, 2, 7, 8, 13); */ 788 | 789 | v[2] = v[2] + v[7] + m[sig_g60[r]]; 790 | v[13] ^= v[2]; 791 | v[13] = (v[13] << 32) | (v[13] >>> 32); 792 | v[8] = v[8] + v[13]; 793 | v[7] ^= v[8]; 794 | v[7] = (v[7] >>> 24) | (v[7] << 40); 795 | v[2] = v[2] + v[7] + m[sig_g61[r]]; 796 | v[13] ^= v[2]; 797 | v[13] = (v[13] >>> 16) | (v[13] << 48); 798 | v[8] = v[8] + v[13]; 799 | v[7] ^= v[8]; 800 | v[7] = (v[7] << 1) | (v[7] >>> 63); 801 | 802 | /** G (r, 7, 3, 4, 9, 14); */ 803 | 804 | v[3] = v[3] + v[4] + m[sig_g70[r]]; 805 | v[14] ^= v[3]; 806 | v[14] = (v[14] << 32) | (v[14] >>> 32); 807 | v[9] = v[9] + v[14]; 808 | v[4] ^= v[9]; 809 | v[4] = (v[4] >>> 24) | (v[4] << 40); 810 | v[3] = v[3] + v[4] + m[sig_g71[r]]; 811 | v[14] ^= v[3]; 812 | v[14] = (v[14] >>> 16) | (v[14] << 48); 813 | v[9] = v[9] + v[14]; 814 | v[4] ^= v[9]; 815 | v[4] = (v[4] << 1) | (v[4] >>> 63); 816 | } 817 | 818 | // Update state vector h 819 | h[0] ^= v[0] ^ v[8]; 820 | h[1] ^= v[1] ^ v[9]; 821 | h[2] ^= v[2] ^ v[10]; 822 | h[3] ^= v[3] ^ v[11]; 823 | h[4] ^= v[4] ^ v[12]; 824 | h[5] ^= v[5] ^ v[13]; 825 | h[6] ^= v[6] ^ v[14]; 826 | h[ 7] ^= v[7] ^ v[15]; 827 | 828 | // Debug.dumpArray("v @ compress end", v); 829 | // Debug.dumpArray("h @ compress end", h); 830 | /* kaamil */ 831 | } 832 | 833 | //////////////////////////////////////////////////////////////////////// 834 | /// Compression Kernel /////////////////////////////////////////// BEGIN 835 | //////////////////////////////////////////////////////////////////////// 836 | 837 | /** 838 | * a little bit of semantics 839 | */ 840 | interface flag { 841 | int last_block = 0; 842 | int last_node = 1; 843 | } 844 | 845 | //////////////////////////////////////////////////////////////////////// 846 | /// Compression Kernel //////////////////////////////////////////// FINI 847 | //////////////////////////////////////////////////////////////////////// 848 | 849 | /* TEMP - remove at will */ 850 | public static class Debug { 851 | public static void dumpState (Blake2b.Engine e, final String mark) { 852 | System.out.format("-- MARK == @ %s @ ===========\n", mark); 853 | dumpArray("register t", e.t); 854 | dumpArray("register h", e.h); 855 | dumpArray("register f", e.f); 856 | dumpArray("register offset", new long[]{e.buflen}); 857 | System.out.format("-- END MARK =================\n"); 858 | } 859 | public static void dumpArray (final String label, final long[] b) { 860 | System.out.format ( "-- %s -- :\n{\n", label ); 861 | for( int j = 0; j < b.length ; ++j ) { 862 | System.out.format ( " [%2d] : %016X\n", j, b[j]); 863 | } 864 | System.out.format ( "}\n" ); 865 | } 866 | public static void dumpBuffer (final PrintStream out, final String label, final byte[] b) { 867 | dumpBuffer(out, label, b, 0, b.length); 868 | } 869 | public static void dumpBuffer (final PrintStream out, final byte[] b) { 870 | dumpBuffer(out, null, b, 0, b.length); 871 | } 872 | public static void dumpBuffer (final PrintStream out, final byte[] b, final int offset, final int len) { 873 | dumpBuffer(out, null, b, offset, len); 874 | } 875 | public static void dumpBuffer (final PrintStream out, final String label, final byte[] b, final int offset, final int len) { 876 | if(label != null) 877 | out.format ( "-- %s -- :\n", label ); 878 | out.format("{\n ", label); 879 | for( int j = 0; j < len ; ++j ) { 880 | out.format ("%02X", b[j + offset]); 881 | if(j+1 < len) { 882 | if ((j+1)%8==0) out.print("\n "); 883 | else out.print(' '); 884 | } 885 | } 886 | out.format("\n}\n"); 887 | } 888 | } 889 | /* TEMP - remove at will */ 890 | 891 | // --------------------------------------------------------------------- 892 | // Helper for assert error messages 893 | // --------------------------------------------------------------------- 894 | public static final class Assert { 895 | public final static String exclusiveUpperBound = "'%s' %d is >= %d"; 896 | public final static String inclusiveUpperBound = "'%s' %d is > %d"; 897 | public final static String exclusiveLowerBound = "'%s' %d is <= %d"; 898 | public final static String inclusiveLowerBound = "'%s' %d is < %d"; 899 | static String assertFail(final String name, final T v, final String err, final T spec) { 900 | new Exception().printStackTrace(); 901 | return String.format(err, name, v, spec); 902 | } 903 | } 904 | // --------------------------------------------------------------------- 905 | // Little Endian Codecs (inlined in the compressor) 906 | /* 907 | * impl note: these are not library funcs and used in hot loops, so no 908 | * null or bounds checks are performed. For our purposes, this is OK. 909 | */ 910 | // --------------------------------------------------------------------- 911 | 912 | public static class LittleEndian { 913 | private static final byte[] hex_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 914 | private static final byte[] HEX_digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 915 | /** @return hex rep of byte (lower case). */ 916 | static public String toHexStr (final byte[] b) { 917 | return toHexStr (b, false); // because String class is slower. 918 | } 919 | static public String toHexStr (final byte[] b, boolean upperCase) { 920 | final int len = b.length; 921 | final byte[] digits = new byte[ len * 2 ]; 922 | final byte[] hex_rep = upperCase ? HEX_digits : hex_digits ; 923 | for (int i = 0; i < len; i++) { 924 | digits [ i*2 ] = hex_rep [ (byte) (b[i] >> 4 & 0x0F) ]; 925 | digits [ i*2+1 ] = hex_rep [ (byte) (b[i] & 0x0F) ]; 926 | } 927 | return new String(digits); 928 | } 929 | public static int readInt (final byte[] b, int off) { 930 | int v0 931 | = ((int)b [ off++ ] & 0xFF ); 932 | v0 |= ((int)b [ off++ ] & 0xFF ) << 8; 933 | v0 |= ((int)b [ off++ ] & 0xFF ) << 16; 934 | v0 |= ((int)b [ off ] ) << 24; 935 | return v0; 936 | } 937 | /** Little endian - byte[] to long */ 938 | public static long readLong (final byte[] b, int off) { 939 | long v0 940 | = ((long)b [ off++ ] & 0xFF ); 941 | v0 |= ((long)b [ off++ ] & 0xFF ) << 8; 942 | v0 |= ((long)b [ off++ ] & 0xFF ) << 16; 943 | v0 |= ((long)b [ off++ ] & 0xFF ) << 24; 944 | v0 |= ((long)b [ off++ ] & 0xFF ) << 32; 945 | v0 |= ((long)b [ off++ ] & 0xFF ) << 40; 946 | v0 |= ((long)b [ off++ ] & 0xFF ) << 48; 947 | v0 |= ((long)b [ off ] ) << 56; 948 | return v0; 949 | } 950 | /** */ 951 | /** Little endian - long to byte[] */ 952 | public static void writeLong (long v, final byte[] b, final int off) { 953 | b [ off ] = (byte) v; v >>>= 8; 954 | b [ off + 1 ] = (byte) v; v >>>= 8; 955 | b [ off + 2 ] = (byte) v; v >>>= 8; 956 | b [ off + 3 ] = (byte) v; v >>>= 8; 957 | b [ off + 4 ] = (byte) v; v >>>= 8; 958 | b [ off + 5 ] = (byte) v; v >>>= 8; 959 | b [ off + 6 ] = (byte) v; v >>>= 8; 960 | b [ off + 7 ] = (byte) v; 961 | } 962 | /** Little endian - int to byte[] */ 963 | public static void writeInt (int v, final byte[] b, final int off) { 964 | b [ off ] = (byte) v; v >>>= 8; 965 | b [ off + 1 ] = (byte) v; v >>>= 8; 966 | b [ off + 2 ] = (byte) v; v >>>= 8; 967 | b [ off + 3 ] = (byte) v; 968 | } 969 | } 970 | } 971 | // --------------------------------------------------------------------- 972 | // digest parameter (block) 973 | // --------------------------------------------------------------------- 974 | /** Blake2b configuration parameters block per spec */ 975 | // REVU: need to review a revert back to non-lazy impl TODO: do & bench 976 | public static class Param implements AlgorithmParameterSpec { 977 | /** 978 | * default bytes of Blake2b parameter block 979 | */ 980 | final static byte[] default_bytes = new byte[Spec.param_bytes]; 981 | /** 982 | * default Blake2b h vector 983 | */ 984 | final static long[] default_h = new long[Spec.state_space_len ]; 985 | 986 | /** initialize default_bytes */ 987 | static { 988 | default_bytes [ Xoff.digest_length ] = Default.digest_length; 989 | default_bytes [ Xoff.key_length ] = Default.key_length; 990 | default_bytes [ Xoff.fanout ] = Default.fanout; 991 | default_bytes [ Xoff.depth ] = Default.depth; 992 | /* def. leaf_length is 0 fill and already set by new byte[] */ 993 | /* def. node_offset is 0 fill and already set by new byte[] */ 994 | default_bytes [ Xoff.node_depth ] = Default.node_depth; 995 | default_bytes [ Xoff.inner_length] = Default.inner_length; 996 | /* def. salt is 0 fill and already set by new byte[] */ 997 | /* def. personal is 0 fill and already set by new byte[] */ 998 | } 999 | 1000 | static { 1001 | default_h [0] = readLong( default_bytes, 0 ); 1002 | default_h [1] = readLong( default_bytes, 8 ); 1003 | default_h [2] = readLong( default_bytes, 16 ); 1004 | default_h [3] = readLong( default_bytes, 24 ); 1005 | default_h [4] = readLong( default_bytes, 32 ); 1006 | default_h [5] = readLong( default_bytes, 40 ); 1007 | default_h [6] = readLong( default_bytes, 48 ); 1008 | default_h [7] = readLong( default_bytes, 56 ); 1009 | 1010 | default_h[0] ^= Spec.IV[0]; 1011 | default_h[1] ^= Spec.IV[1]; 1012 | default_h[2] ^= Spec.IV[2]; 1013 | default_h[3] ^= Spec.IV[3]; 1014 | default_h[4] ^= Spec.IV[4]; 1015 | default_h[5] ^= Spec.IV[5]; 1016 | default_h[6] ^= Spec.IV[6]; 1017 | default_h[7] ^= Spec.IV[7]; 1018 | } 1019 | 1020 | /** */ 1021 | private final long[] h = new long [ Spec.state_space_len ]; 1022 | /** */ 1023 | private boolean hasKey = false; 1024 | /** not sure how to make this secure - TODO */ 1025 | private byte[] key_bytes = null; 1026 | /** */ 1027 | private byte[] bytes = null; 1028 | /** */ 1029 | public Param() { 1030 | System.arraycopy( default_h, 0, h, 0, Spec.state_space_len ); 1031 | } 1032 | 1033 | /** */ 1034 | public long[] initialized_H () { 1035 | return h; 1036 | } 1037 | 1038 | /** package only - copy returned - do not use in functional loops */ 1039 | public byte[] getBytes() { 1040 | lazyInitBytes(); 1041 | byte[] copy = new byte[ bytes.length ]; 1042 | System.arraycopy( bytes, 0, copy, 0, bytes.length ); 1043 | return copy; 1044 | } 1045 | 1046 | final byte getByteParam (final int xoffset) { 1047 | byte[] _bytes = bytes; 1048 | if(_bytes == null) _bytes = Param.default_bytes; 1049 | return _bytes[ xoffset]; 1050 | } 1051 | 1052 | final int getIntParam (final int xoffset) { 1053 | byte[] _bytes = bytes; 1054 | if(_bytes == null) _bytes = Param.default_bytes; 1055 | return readInt ( _bytes, xoffset); 1056 | } 1057 | 1058 | final long getLongParam (final int xoffset) { 1059 | byte[] _bytes = bytes; 1060 | if(_bytes == null) _bytes = Param.default_bytes; 1061 | return readLong ( _bytes, xoffset); 1062 | } 1063 | 1064 | // TODO same for tree params depth, fanout, inner, node-depth, node-offset 1065 | public final int getDigestLength() { 1066 | return (int) getByteParam ( Xoff.digest_length ); 1067 | } 1068 | 1069 | /* 0-7 inclusive */ 1070 | public final Param setDigestLength(int len) { 1071 | assert len > 0 : assertFail("len", len, exclusiveLowerBound, 0); 1072 | assert len <= Spec.max_digest_bytes : assertFail("len", len, inclusiveUpperBound, Spec.max_digest_bytes); 1073 | 1074 | lazyInitBytes(); 1075 | bytes[Xoff.digest_length] = (byte) len; 1076 | h[0] = readLong(bytes, 0); 1077 | h[0] ^= Spec.IV[0]; 1078 | return this; 1079 | } 1080 | 1081 | public final int getKeyLength() { 1082 | return (int) getByteParam(Xoff.key_length); 1083 | } 1084 | 1085 | public final int getFanout() { 1086 | return (int) getByteParam(Xoff.fanout); 1087 | } 1088 | 1089 | public final Param setFanout(int fanout) { 1090 | assert fanout > 0 : assertFail("fanout", fanout, exclusiveLowerBound, 0); 1091 | 1092 | lazyInitBytes(); 1093 | bytes[Xoff.fanout] = (byte) fanout; 1094 | h[0] = readLong(bytes, 0); 1095 | h[0] ^= Spec.IV[0]; 1096 | return this; 1097 | } 1098 | 1099 | public final int getDepth() { 1100 | return (int) getByteParam(Xoff.depth); 1101 | } 1102 | 1103 | public final Param setDepth(int depth) { 1104 | assert depth > 0 : assertFail("depth", depth, exclusiveLowerBound, 0); 1105 | 1106 | lazyInitBytes(); 1107 | bytes[Xoff.depth] = (byte) depth; 1108 | h[0] = readLong(bytes, 0); 1109 | h[0] ^= Spec.IV[0]; 1110 | return this; 1111 | } 1112 | 1113 | public final int getLeafLength() { 1114 | return getIntParam(Xoff.leaf_length); 1115 | } 1116 | 1117 | public final Param setLeafLength(int leaf_length) { 1118 | assert leaf_length >= 0 : assertFail("leaf_length", leaf_length, inclusiveLowerBound, 0); 1119 | 1120 | lazyInitBytes(); 1121 | writeInt(leaf_length, bytes, Xoff.leaf_length); 1122 | h[0] = readLong(bytes, 0); 1123 | h[0] ^= Spec.IV[0]; 1124 | return this; 1125 | } 1126 | 1127 | public final long getNodeOffset() { 1128 | return getLongParam ( Xoff.node_offset); 1129 | } 1130 | 1131 | /* 8-15 inclusive */ 1132 | public final Param setNodeOffset(long node_offset) { 1133 | assert node_offset >= 0 : assertFail("node_offset", node_offset, inclusiveLowerBound, 0); 1134 | 1135 | lazyInitBytes(); 1136 | writeLong(node_offset, bytes, Xoff.node_offset); 1137 | h[1] = readLong(bytes, Xoff.node_offset); 1138 | h[1] ^= Spec.IV[1]; 1139 | return this; 1140 | } 1141 | 1142 | public final int getNodeDepth() { 1143 | return (int) getByteParam(Xoff.node_depth); 1144 | } 1145 | 1146 | /* 16-23 inclusive */ 1147 | public final Param setNodeDepth(int node_depth) { 1148 | assert node_depth >= 0 : assertFail("node_depth", node_depth, inclusiveLowerBound, 0); 1149 | 1150 | lazyInitBytes(); 1151 | bytes[Xoff.node_depth] = (byte) node_depth; 1152 | h[2] = readLong(bytes, Xoff.node_depth); 1153 | h[2] ^= Spec.IV[2]; 1154 | h[3] = readLong(bytes, Xoff.node_depth + 8); 1155 | h[3] ^= Spec.IV[3]; 1156 | return this; 1157 | } 1158 | 1159 | public final int getInnerLength() { 1160 | return (int) getByteParam(Xoff.inner_length ); 1161 | } 1162 | 1163 | public final Param setInnerLength(int inner_length) { 1164 | assert inner_length >= 0 : assertFail("inner_length", inner_length, inclusiveLowerBound, 0); 1165 | 1166 | lazyInitBytes(); 1167 | bytes[Xoff.inner_length] = (byte) inner_length; 1168 | h[2] = readLong(bytes, Xoff.node_depth); 1169 | h[2] ^= Spec.IV[2]; 1170 | h[3] = readLong(bytes, Xoff.node_depth + 8); 1171 | h[3] ^= Spec.IV[3]; 1172 | return this; 1173 | } 1174 | 1175 | public final boolean hasKey() { 1176 | return this.hasKey; 1177 | } 1178 | 1179 | @Override 1180 | public Param clone() { 1181 | final Param clone = new Param(); 1182 | System.arraycopy(this.h, 0, clone.h, 0, h.length); 1183 | clone.lazyInitBytes(); 1184 | System.arraycopy(this.bytes, 0, clone.bytes, 0, this.bytes.length); 1185 | 1186 | if (this.hasKey) { 1187 | clone.hasKey = this.hasKey; 1188 | clone.key_bytes = new byte[Spec.max_key_bytes * 2]; 1189 | System.arraycopy(this.key_bytes, 0, clone.key_bytes, 0, this.key_bytes.length); 1190 | } 1191 | return clone; 1192 | } 1193 | 1194 | //////////////////////////////////////////////////////////////////////// 1195 | /// lazy setters - write directly to the bytes image of param block //// 1196 | //////////////////////////////////////////////////////////////////////// 1197 | final void lazyInitBytes() { 1198 | if (bytes == null) { 1199 | bytes = new byte[Spec.param_bytes]; 1200 | System.arraycopy(Param.default_bytes, 0, bytes, 0, Spec.param_bytes); 1201 | } 1202 | } 1203 | 1204 | public final Param setKey(final Key key) { 1205 | assert key != null : "key is null"; 1206 | final byte[] keybytes = key.getEncoded(); 1207 | assert keybytes != null : "key.encoded() is null"; 1208 | 1209 | return this.setKey(keybytes); 1210 | } 1211 | 1212 | public final Param setKey(final byte[] key) { 1213 | assert key != null : "key is null"; 1214 | assert key.length >= 0 : assertFail("key.length", key.length, inclusiveUpperBound, 0); 1215 | assert key.length <= Spec.max_key_bytes : assertFail("key.length", key.length, inclusiveUpperBound, Spec.max_key_bytes); 1216 | 1217 | // zeropad keybytes 1218 | this.key_bytes = new byte[Spec.max_key_bytes * 2]; 1219 | System.arraycopy(key, 0, this.key_bytes, 0, key.length); 1220 | lazyInitBytes(); 1221 | bytes[Xoff.key_length] = (byte) key.length; // checked c ref; this is correct 1222 | h[0] = readLong(bytes, 0); 1223 | h[0] ^= Spec.IV[0]; 1224 | this.hasKey = true; 1225 | return this; 1226 | } 1227 | 1228 | /* 32-47 inclusive */ 1229 | public final Param setSalt(final byte[] salt) { 1230 | assert salt != null : "salt is null"; 1231 | assert salt.length <= Spec.max_salt_bytes : assertFail("salt.length", salt.length, inclusiveUpperBound, Spec.max_salt_bytes); 1232 | 1233 | lazyInitBytes(); 1234 | Arrays.fill ( bytes, Xoff.salt, Xoff.salt + Spec.max_salt_bytes, (byte)0); 1235 | System.arraycopy( salt, 0, bytes, Xoff.salt, salt.length ); 1236 | h[ 4 ] = readLong( bytes, Xoff.salt ); 1237 | h[ 4 ] ^= Spec.IV [ 4 ]; 1238 | h[ 5 ] = readLong( bytes, Xoff.salt + 8 ); 1239 | h[ 5 ] ^= Spec.IV [ 5 ]; 1240 | return this; 1241 | } 1242 | 1243 | /* 48-63 inclusive */ 1244 | public final Param setPersonal(byte[] personal) { 1245 | assert personal != null : "personal is null"; 1246 | assert personal.length <= Spec.max_personalization_bytes : assertFail("personal.length", personal.length, inclusiveUpperBound, Spec.max_personalization_bytes); 1247 | 1248 | lazyInitBytes(); 1249 | Arrays.fill(bytes, Xoff.personal, Xoff.personal + Spec.max_personalization_bytes, (byte) 0); 1250 | System.arraycopy(personal, 0, bytes, Xoff.personal, personal.length); 1251 | h[6] = readLong(bytes, Xoff.personal); 1252 | h[6] ^= Spec.IV[6]; 1253 | h[7] = readLong(bytes, Xoff.personal + 8); 1254 | h[7] ^= Spec.IV[7]; 1255 | return this; 1256 | } 1257 | 1258 | /* 24-31 masked by reserved and remain unchanged */ 1259 | 1260 | interface Xoff { 1261 | int digest_length = 0; 1262 | int key_length = 1; 1263 | int fanout = 2; 1264 | int depth = 3; 1265 | int leaf_length = 4; 1266 | int node_offset = 8; 1267 | int node_depth = 16; 1268 | int inner_length = 17; 1269 | int reserved = 18; 1270 | int salt = 32; 1271 | int personal = 48; 1272 | } 1273 | 1274 | public interface Default { 1275 | byte digest_length = Spec.max_digest_bytes; 1276 | byte key_length = 0; 1277 | byte fanout = 1; 1278 | byte depth = 1; 1279 | int leaf_length = 0; 1280 | long node_offset = 0; 1281 | byte node_depth = 0; 1282 | byte inner_length = 0; 1283 | } 1284 | //////////////////////////////////////////////////////////////////////// 1285 | /// lazy setters /////////////////////////////////////////////////// END 1286 | //////////////////////////////////////////////////////////////////////// 1287 | } 1288 | } 1289 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/exception/Argon2Exception.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.exception; 2 | 3 | /* dislike checked exceptions */ 4 | class Argon2Exception extends RuntimeException { 5 | Argon2Exception(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/exception/Argon2InvalidParameterException.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.exception; 2 | 3 | public class Argon2InvalidParameterException extends Argon2Exception{ 4 | public Argon2InvalidParameterException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/model/Argon2Type.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.model; 2 | 3 | public enum Argon2Type { 4 | Argon2d, Argon2i, Argon2id; 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/model/Block.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.model; 2 | 3 | 4 | import at.gadermaier.argon2.Util; 5 | 6 | import java.util.Arrays; 7 | 8 | import static at.gadermaier.argon2.Constants.ARGON2_BLOCK_SIZE; 9 | import static at.gadermaier.argon2.Constants.ARGON2_QWORDS_IN_BLOCK; 10 | 11 | public class Block { 12 | 13 | /* 128 * 8 Byte QWords */ 14 | public long[] v; 15 | 16 | public Block() { 17 | v = new long[ARGON2_QWORDS_IN_BLOCK]; 18 | } 19 | 20 | public void fromBytes(byte[] input) { 21 | assert (input.length == ARGON2_BLOCK_SIZE); 22 | 23 | for (int i = 0; i < v.length; i++) { 24 | byte[] slice = Arrays.copyOfRange(input, i * 8, (i + 1) * 8); 25 | v[i] = Util.littleEndianBytesToLong(slice); 26 | } 27 | } 28 | 29 | public byte[] toBytes() { 30 | byte[] result = new byte[ARGON2_BLOCK_SIZE]; 31 | 32 | for (int i = 0; i < v.length; i++) { 33 | byte[] bytes = Util.longToLittleEndianBytes(v[i]); 34 | System.arraycopy(bytes, 0, result, i * bytes.length, bytes.length); 35 | } 36 | 37 | return result; 38 | } 39 | 40 | public void copyBlock(Block other) { 41 | System.arraycopy(other.v, 0, v, 0, v.length); 42 | } 43 | 44 | public void xor(Block b1, Block b2) { 45 | for (int i = 0; i < v.length; i++) { 46 | v[i] = b1.v[i] ^ b2.v[i]; 47 | } 48 | } 49 | 50 | public void xor(Block b1, Block b2, Block b3) { 51 | for (int i = 0; i < v.length; i++) { 52 | v[i] = b1.v[i] ^ b2.v[i] ^ b3.v[i]; 53 | } 54 | } 55 | 56 | public void xorWith(Block other) { 57 | for (int i = 0; i < v.length; i++) { 58 | v[i] = v[i] ^ other.v[i]; 59 | } 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | StringBuilder result = new StringBuilder(); 65 | for (long value : v) { 66 | result.append(Util.bytesToHexString(Util.longToLittleEndianBytes(value))); 67 | } 68 | 69 | return result.toString(); 70 | } 71 | 72 | void clear() { 73 | Arrays.fill(v, 0); 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/model/Instance.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.model; 2 | 3 | import at.gadermaier.argon2.Argon2; 4 | 5 | import static at.gadermaier.argon2.Constants.ARGON2_SYNC_POINTS; 6 | 7 | public class Instance { 8 | 9 | public Block[] memory; 10 | private int version; 11 | private int iterations; 12 | private int segmentLength; 13 | private int laneLength; 14 | private int lanes; 15 | 16 | private Argon2Type type; 17 | 18 | public Instance(Argon2 argon2) { 19 | this.version = argon2.getVersion(); 20 | this.iterations = argon2.getIterations(); 21 | this.lanes = argon2.getLanes(); 22 | this.type = argon2.getType(); 23 | 24 | /* 2. Align memory size */ 25 | /* Minimum memoryBlocks = 8L blocks, where L is the number of lanes */ 26 | int memoryBlocks = argon2.getMemory(); 27 | 28 | if (memoryBlocks < 2 * ARGON2_SYNC_POINTS * argon2.getLanes()) { 29 | memoryBlocks = 2 * ARGON2_SYNC_POINTS * argon2.getLanes(); 30 | } 31 | 32 | this.segmentLength = memoryBlocks / (argon2.getLanes() * ARGON2_SYNC_POINTS); 33 | this.laneLength = segmentLength * ARGON2_SYNC_POINTS; 34 | /* Ensure that all segments have equal length */ 35 | memoryBlocks = segmentLength * (argon2.getLanes() * ARGON2_SYNC_POINTS); 36 | 37 | initMemory(memoryBlocks); 38 | } 39 | 40 | private void initMemory(int memoryBlocks) { 41 | this.memory = new Block[memoryBlocks]; 42 | 43 | for (int i = 0; i < memory.length; i++) { 44 | memory[i] = new Block(); 45 | } 46 | } 47 | 48 | public void clear() { 49 | for (Block b : memory) { 50 | b.clear(); 51 | } 52 | 53 | memory = null; 54 | } 55 | 56 | public Block[] getMemory() { 57 | return memory; 58 | } 59 | 60 | public int getVersion() { 61 | return version; 62 | } 63 | 64 | public int getIterations() { 65 | return iterations; 66 | } 67 | 68 | public int getSegmentLength() { 69 | return segmentLength; 70 | } 71 | 72 | public int getLaneLength() { 73 | return laneLength; 74 | } 75 | 76 | public int getLanes() { 77 | return lanes; 78 | } 79 | 80 | public Argon2Type getType() { 81 | return type; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/at/gadermaier/argon2/model/Position.java: -------------------------------------------------------------------------------- 1 | package at.gadermaier.argon2.model; 2 | 3 | public class Position { 4 | 5 | public int pass; 6 | public int lane; 7 | public int slice; 8 | public int index; 9 | 10 | public Position(int pass, int lane, int slice, int index) { 11 | this.pass = pass; 12 | this.lane = lane; 13 | this.slice = slice; 14 | this.index = index; 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/test/java/Argon2Test.java: -------------------------------------------------------------------------------- 1 | import at.gadermaier.argon2.Argon2Factory; 2 | import org.junit.Test; 3 | 4 | import static at.gadermaier.argon2.Constants.ARGON2_VERSION_10; 5 | import static at.gadermaier.argon2.Constants.Defaults.ARGON2_VERSION_NUMBER; 6 | import static at.gadermaier.argon2.Constants.Defaults.OUTLEN_DEF; 7 | import static org.junit.Assert.fail; 8 | 9 | public class Argon2Test { 10 | 11 | @Test 12 | public void basicTest(){ 13 | 14 | boolean largeRam = false; 15 | 16 | int version = ARGON2_VERSION_10; 17 | System.out.println("Test Argon2i version number: " + version); 18 | /* Multiple test cases for various input values */ 19 | hashtest(version, 2, 16, 1, "password", "somesalt", 20 | "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", 21 | "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + 22 | "$9sTbSlTio3Biev89thdrlKKiCaYsjjYVJxGAL3swxpQ", OUTLEN_DEF); 23 | if(largeRam){ 24 | 25 | hashtest(version, 2, 20, 1, "password", "somesalt", 26 | "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9", 27 | "$argon2i$m=1048576,t=2,p=1$c29tZXNhbHQ" + 28 | "$lpDsVdKNPtMlYvLnPqYrArAYdXZDoq5ueVKEWd6BBuk", OUTLEN_DEF); 29 | 30 | hashtest(version, 2, 18, 1, "password", "somesalt", 31 | "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467", 32 | "$argon2i$m=262144,t=2,p=1$c29tZXNhbHQ" + 33 | "$Pmiaqj0op3zyvHKlGsUxZnYXURgvHuKS4/Z3p9pMJGc", OUTLEN_DEF); 34 | } 35 | hashtest(version, 2, 8, 1, "password", "somesalt", 36 | "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06", 37 | "$argon2i$m=256,t=2,p=1$c29tZXNhbHQ" + 38 | "$/U3YPXYsSb3q9XxHvc0MLxur+GP960kN9j7emXX8zwY", OUTLEN_DEF); 39 | hashtest(version, 2, 8, 2, "password", "somesalt", 40 | "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb", 41 | "$argon2i$m=256,t=2,p=2$c29tZXNhbHQ" + 42 | "$tsEVYKap1h6scGt5ovl9aLRGOqOth+AMB+KwHpDFZPs", OUTLEN_DEF); 43 | hashtest(version, 1, 16, 1, "password", "somesalt", 44 | "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2", 45 | "$argon2i$m=65536,t=1,p=1$c29tZXNhbHQ" + 46 | "$gWMFUrjzsfSM2xmSxMZ4ZD1JCytetP9sSzQ4tWIXJLI", OUTLEN_DEF); 47 | hashtest(version, 4, 16, 1, "password", "somesalt", 48 | "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b", 49 | "$argon2i$m=65536,t=4,p=1$c29tZXNhbHQ" + 50 | "$8hLwFhXm6110c03D70Ct4tUdBSRo2MaUQKOh8sHChHs", OUTLEN_DEF); 51 | hashtest(version, 2, 16, 1, "differentpassword", "somesalt", 52 | "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3", 53 | "$argon2i$m=65536,t=2,p=1$c29tZXNhbHQ" + 54 | "$6ckCB0tnVFMaOgvlGeW69ASzDOabPwGsO/ISKZYBCaM", OUTLEN_DEF); 55 | hashtest(version, 2, 16, 1, "password", "diffsalt", 56 | "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497", 57 | "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ" + 58 | "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc", OUTLEN_DEF); 59 | 60 | hashtest(version, 2, 16, 1, "password", "diffsalt", 61 | "1a097a5d1c80e579583f6e19c7e4763ccb7c522ca85b7d58143738e12ca39f8e6e42734c950ff2463675b97c37ba39feba4a9cd9cc5b4c798f2aaf70eb4bd044c8d148decb569870dbd923430b82a083f284beae777812cce18cdac68ee8ccefc6ec9789f30a6b5a034591f51af830f4", 62 | "$argon2i$m=65536,t=2,p=1$ZGlmZnNhbHQ" + 63 | "$eaEDuQ/orvhXDLMfyLIiWXeJFvgza3vaw4kladTxxJc", 112); 64 | 65 | 66 | version = ARGON2_VERSION_NUMBER; 67 | System.out.println("Test Argon2i version number: " + version); 68 | 69 | /* Multiple test cases for various input values */ 70 | hashtest(version, 2, 16, 1, "password", "somesalt", 71 | "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0", 72 | "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + 73 | "$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", OUTLEN_DEF); 74 | if(largeRam) { 75 | hashtest(version, 2, 20, 1, "password", "somesalt", 76 | "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41", 77 | "$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ" + 78 | "$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E", OUTLEN_DEF); 79 | 80 | hashtest(version, 2, 18, 1, "password", "somesalt", 81 | "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb", 82 | "$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ" + 83 | "$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s", OUTLEN_DEF); 84 | } 85 | hashtest(version, 2, 8, 1, "password", "somesalt", 86 | "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f", 87 | "$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ" + 88 | "$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8", OUTLEN_DEF); 89 | hashtest(version, 2, 8, 2, "password", "somesalt", 90 | "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61", 91 | "$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ" + 92 | "$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E", OUTLEN_DEF); 93 | hashtest(version, 1, 16, 1, "password", "somesalt", 94 | "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf", 95 | "$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ" + 96 | "$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8", OUTLEN_DEF); 97 | hashtest(version, 4, 16, 1, "password", "somesalt", 98 | "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b", 99 | "$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ" + 100 | "$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls", OUTLEN_DEF); 101 | hashtest(version, 2, 16, 1, "differentpassword", "somesalt", 102 | "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee", 103 | "$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ" + 104 | "$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4", OUTLEN_DEF); 105 | hashtest(version, 2, 16, 1, "password", "diffsalt", 106 | "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271", 107 | "$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ" + 108 | "$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE", OUTLEN_DEF); 109 | } 110 | 111 | private void hashtest(int version, int iterations, int memory, int parallelism, 112 | String password, String salt, String passwordRef, String mcfref, int outputLength) { 113 | 114 | 115 | String result = Argon2Factory.create() 116 | .setVersion(version) 117 | .setIterations(iterations) 118 | .setMemory(memory) 119 | .setParallelism(parallelism) 120 | .setOutputLength(outputLength) 121 | .hash(password.toCharArray(), salt); 122 | 123 | if (!result.equals(passwordRef)) { 124 | fail(); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/test/java/BaseTest.java: -------------------------------------------------------------------------------- 1 | import at.gadermaier.argon2.Argon2; 2 | import at.gadermaier.argon2.Argon2Factory; 3 | import org.junit.Before; 4 | 5 | public abstract class BaseTest { 6 | 7 | protected Argon2 argon2; 8 | 9 | @Before 10 | public void setUp(){ 11 | argon2 = Argon2Factory.create() 12 | .setPassword("password".toCharArray()) 13 | .setSalt("saltsalt"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/InitializeTest.java: -------------------------------------------------------------------------------- 1 | import at.gadermaier.argon2.algorithm.Initialize; 2 | import at.gadermaier.argon2.model.Instance; 3 | import org.junit.Test; 4 | 5 | import static junit.framework.TestCase.assertEquals; 6 | 7 | public class InitializeTest extends BaseTest { 8 | 9 | private String instanceNull = "0011a4db4b4dc5422bfab9973caf41bd78d9b20f9a01c236e329c65ffa67c2e6d655eada0eddbc82fe29d0a8fc33ca267e76889ac563e5fcf2a61cb395bd32404a9f9f6bed4324328e4671614efd85ebaa3ff319a4b5996c3fb04e85188839580c945aa12081d3496c6f9a25bf3214d0f766e54c372361a0f3d62ad7acc5cb0306b8fca890e0fcdf932597e3f819ff1ae836976dae0af12b8d53036d1cff4b3bbf5a25de57828ed2de7baa364f0b32ff3ce0626c7cb1e3b76d9bf9a7857e051c1c7a3368792fa1a01a79a7b6c83f97a2cfb3c40c9a7c5f3616673f1f97716a10c6e27a950fb737aab6c544ab59bff3f328a13acf432942c0096420ac7a1ed2de34c181aaf71802ed9a56184476b983e011a50a6203f628d9028d1b442c006d95cbe819acc754451862eab50d7df1ec6ac6bcd55169a7c64f00a3305609df52a178498c44e1d11adf56661e600eeeaf5132864fb99e937cfd3173141e3e619451f1b774719fe6c9d16a73edad3fd494e7520cdefe9e77e210ae2bff00d398e91d6a387775e0a6d9806dc88fa4c481bf4968565cd82df21d135d3bba1cb64c6b65a99d56dd55143f6658d99a5e2c6768394a1036e9cf32fdbaaf704a28d6671423ceb5b54074eb0bde342d541b597a27bf6eced39c168f47da2650df61f96280c1c0f3b858d51534061180c7185ff5f0293a76be3a165ad547303c81c7a480e9eaeddf7f5770b90c3600535b1b3f4be981c357fe08f8db0405ff7d4bc7e5fa94653038aa72ea2f4d4bbb6eb7e5ac76166c57151f0f9c1d26e0307e0d037119e647d33399e8bd0a66b60d18bd0e53af50658e8288b3e829365743abb199c5c59cc910756eb6eacd2a1d73646e47215998d96458be9b00ebf04fc46cdd651d02339822400b5a9565ba11e4b368fbcbdc6ee047ef6e93e66fc08aa0b24349f929d6d3122f2b96b683d709a9c18f584914df5397cf106076fe63823c63470b4c641a7057cf6a690956b6c03db91133db7620cb5e929204a0771c17ac3edb4778e95cb41173c91db45740e1023493242b684cefa0544e384adc8913c4e7bd4711088c2b87d1b922c59bed69a5afbc241cc270268eab791969e3d4181199295af1562631cc5147f8e17607620d965509623ff65261319f2084fb670e473fa990f2b52a6a3fe9dd9b4630e124d7c1b21df4fe4db64b53d4e8c1be5f50093d271a2a7818518ecb786f3c5d36555d348eb3f26fe7031d491167f1c8cd1974e75eb3a205949b3f8b4be0d7dffdee49069f6fa23bd8dec2d950aad3bacae2d3208d543171868665f9d1d6837dab20672d25a32b6794cfc1492a8cf06dcc142a9ca91dc81f00d20038fd7e26e0af42e2a4727a3b4f7b49a17cf3f660635a18063773e3999c3bda22e749b4cb7da41c455ac3e261d64e992d58e28f8157687c5ace8d26349544b3"; 10 | 11 | @Test 12 | public void basicTest(){ 13 | 14 | Instance instance = new Instance(argon2); 15 | Initialize.initialize(instance, argon2); 16 | 17 | assertEquals(instanceNull, instance.memory[0].toString()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/MainSuite.java: -------------------------------------------------------------------------------- 1 | import org.junit.runner.RunWith; 2 | import org.junit.runners.Suite; 3 | import org.junit.runners.Suite.SuiteClasses; 4 | 5 | @RunWith(Suite.class) 6 | @SuiteClasses({ 7 | Argon2Test.class, 8 | InitializeTest.class 9 | }) 10 | public class MainSuite { 11 | } 12 | --------------------------------------------------------------------------------