-
Notifications
You must be signed in to change notification settings - Fork 306
Expand file tree
/
Copy pathArgon2.java
More file actions
217 lines (194 loc) · 6.89 KB
/
Argon2.java
File metadata and controls
217 lines (194 loc) · 6.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.firebase.auth.hash;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.BaseEncoding;
import com.google.firebase.auth.UserImportHash;
import java.util.Map;
/**
* Represents the Argon2 password hashing algorithm. Can be used as an instance of {@link
* com.google.firebase.auth.UserImportHash} when importing users.
*/
public final class Argon2 extends UserImportHash {
private static final int MIN_HASH_LENGTH_BYTES = 4;
private static final int MAX_HASH_LENGTH_BYTES = 1024;
private static final int MIN_PARALLELISM = 1;
private static final int MAX_PARALLELISM = 16;
private static final int MIN_ITERATIONS = 1;
private static final int MAX_ITERATIONS = 16;
private static final int MIN_MEMORY_COST_KIB = 1;
private static final int MAX_MEMORY_COST_KIB = 32768;
private final int hashLengthBytes;
private final Argon2HashType hashType;
private final int parallelism;
private final int iterations;
private final int memoryCostKib;
private final Argon2Version version;
private final String associatedData;
private Argon2(Builder builder) {
super("ARGON2");
checkArgument(intShouldBeBetweenLimitsInclusive(builder.hashLengthBytes, MIN_HASH_LENGTH_BYTES,
MAX_HASH_LENGTH_BYTES),
"hashLengthBytes is required for Argon2 and must be between %s and %s",
MIN_HASH_LENGTH_BYTES, MAX_HASH_LENGTH_BYTES);
checkArgument(builder.hashType != null,
"A hashType is required for Argon2");
checkArgument(
intShouldBeBetweenLimitsInclusive(builder.parallelism, MIN_PARALLELISM, MAX_PARALLELISM),
"parallelism is required for Argon2 and must be between %s and %s", MIN_PARALLELISM,
MAX_PARALLELISM);
checkArgument(
intShouldBeBetweenLimitsInclusive(builder.iterations, MIN_ITERATIONS, MAX_ITERATIONS),
"iterations is required for Argon2 and must be between %s and %s", MIN_ITERATIONS,
MAX_ITERATIONS);
checkArgument(intShouldBeBetweenLimitsInclusive(builder.memoryCostKib, MIN_MEMORY_COST_KIB,
MAX_MEMORY_COST_KIB),
"memoryCostKib is required for Argon2 and must be less than or equal to %s",
MAX_MEMORY_COST_KIB);
this.hashLengthBytes = builder.hashLengthBytes;
this.hashType = builder.hashType;
this.parallelism = builder.parallelism;
this.iterations = builder.iterations;
this.memoryCostKib = builder.memoryCostKib;
if (builder.version != null) {
this.version = builder.version;
} else {
this.version = null;
}
if (builder.associatedData != null) {
this.associatedData = BaseEncoding.base64Url().encode(builder.associatedData);
} else {
this.associatedData = null;
}
}
private static boolean intShouldBeBetweenLimitsInclusive(int property, int fromInclusive,
int toInclusive) {
return property >= fromInclusive && property <= toInclusive;
}
@Override
protected Map<String, Object> getOptions() {
ImmutableMap.Builder<String, Object> argon2Parameters = ImmutableMap.<String, Object>builder()
.put("hashLengthBytes", hashLengthBytes)
.put("hashType", hashType.toString())
.put("parallelism", parallelism)
.put("iterations", iterations)
.put("memoryCostKib", memoryCostKib);
if (this.associatedData != null) {
argon2Parameters.put("associatedData", associatedData);
}
if (this.version != null) {
argon2Parameters.put("version", version.toString());
}
return ImmutableMap.<String, Object>of("argon2Parameters", argon2Parameters.build());
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private int hashLengthBytes;
private Argon2HashType hashType;
private int parallelism;
private int iterations;
private int memoryCostKib;
private Argon2Version version;
private byte[] associatedData;
private Builder() {}
/**
* Sets the hash length in bytes. Required field.
*
* @param hashLengthBytes an integer between 4 and 1024 (inclusive).
* @return This builder.
*/
public Builder setHashLengthBytes(int hashLengthBytes) {
this.hashLengthBytes = hashLengthBytes;
return this;
}
/**
* Sets the Argon2 hash type. Required field.
*
* @param hashType a value from the {@link Argon2HashType} enum.
* @return This builder.
*/
public Builder setHashType(Argon2HashType hashType) {
this.hashType = hashType;
return this;
}
/**
* Sets the degree of parallelism, also called threads or lanes. Required field.
*
* @param parallelism an integer between 1 and 16 (inclusive).
* @return This builder.
*/
public Builder setParallelism(int parallelism) {
this.parallelism = parallelism;
return this;
}
/**
* Sets the number of iterations to perform. Required field.
*
* @param iterations an integer between 1 and 16 (inclusive).
* @return This builder.
*/
public Builder setIterations(int iterations) {
this.iterations = iterations;
return this;
}
/**
* Sets the memory cost in kibibytes. Required field.
*
* @param memoryCostKib an integer between 1 and 32768 (inclusive).
* @return This builder.
*/
public Builder setMemoryCostKib(int memoryCostKib) {
this.memoryCostKib = memoryCostKib;
return this;
}
/**
* Sets the version of the Argon2 algorithm.
*
* @param version a value from the {@link Argon2Version} enum.
* @return This builder.
*/
public Builder setVersion(Argon2Version version) {
this.version = version;
return this;
}
/**
* Sets additional associated data, if provided, to append to the hash value for additional
* security. This data is base64 encoded before it is sent to the API.
*
* @param associatedData Associated data as a byte array.
* @return This builder.
*/
public Builder setAssociatedData(byte[] associatedData) {
this.associatedData = associatedData;
return this;
}
public Argon2 build() {
return new Argon2(this);
}
}
public enum Argon2HashType {
ARGON2_D,
ARGON2_ID,
ARGON2_I
}
public enum Argon2Version {
VERSION_10,
VERSION_13
}
}