├── .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 |
--------------------------------------------------------------------------------