This repository has been archived by the owner on Oct 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
378 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,141 @@ | ||
package dev.medzik.libcrypto; | ||
|
||
public class Argon2 { | ||
import com.password4j.Argon2Function; | ||
import com.password4j.Hash; | ||
import com.password4j.Password; | ||
|
||
public final class Argon2 { | ||
private final int hashLength; | ||
private final int parallelism; | ||
private final int memory; | ||
private final int iterations; | ||
private final Argon2Type type; | ||
private final int version; | ||
|
||
public static final int ARGON2_VERSION_10 = 0x10; | ||
public static final int ARGON2_VERSION_13 = 0x13; | ||
|
||
public final static class Builder { | ||
private int hashLength; | ||
private int parallelism; | ||
private int memory; | ||
private int iterations; | ||
private Argon2Type type; | ||
private int version; | ||
|
||
public Builder() { | ||
this.hashLength = 32; | ||
this.parallelism = 1; | ||
this.memory = 65536; | ||
this.iterations = 3; | ||
this.type = Argon2Type.ID; | ||
this.version = ARGON2_VERSION_13; | ||
} | ||
|
||
public Builder setHashLength(int hashLength) { | ||
this.hashLength = hashLength; | ||
return this; | ||
} | ||
|
||
public Builder setParallelism(int parallelism) { | ||
this.parallelism = parallelism; | ||
return this; | ||
} | ||
|
||
public Builder setMemory(int memory) { | ||
this.memory = memory; | ||
return this; | ||
} | ||
|
||
public Builder setIterations(int iterations) { | ||
this.iterations = iterations; | ||
return this; | ||
} | ||
|
||
public Builder setType(Argon2Type type) { | ||
this.type = type; | ||
return this; | ||
} | ||
|
||
public Builder setVersion(int version) { | ||
this.version = version; | ||
return this; | ||
} | ||
|
||
public Argon2 build() { | ||
return new Argon2(hashLength, parallelism, memory, iterations, type, version); | ||
} | ||
} | ||
|
||
/** | ||
* Creates a new instance of Argon2 hasher with the given parameters. | ||
* @param hashLength length of the hash | ||
* @param parallelism number of parallel threads to use when hashing | ||
* @param memory amount of memory to use when hashing | ||
* @param iterations number of iterations to use when hashing | ||
*/ | ||
public Argon2(int hashLength, int parallelism, int memory, int iterations) { | ||
this.hashLength = hashLength; | ||
this.parallelism = parallelism; | ||
this.memory = memory; | ||
this.iterations = iterations; | ||
this.type = Argon2Type.ID; | ||
this.version = ARGON2_VERSION_13; | ||
} | ||
|
||
/** | ||
* Creates a new instance of Argon2 hasher with the given parameters. | ||
* @param hashLength length of the hash | ||
* @param parallelism number of parallel threads to use when hashing | ||
* @param memory amount of memory to use when hashing | ||
* @param iterations number of iterations to use when hashing | ||
* @param type type argon2 to use (i, d, id) {@link Argon2Type} | ||
* @param version hasher version | ||
*/ | ||
public Argon2(int hashLength, int parallelism, int memory, int iterations, Argon2Type type, int version) { | ||
this.hashLength = hashLength; | ||
this.parallelism = parallelism; | ||
this.memory = memory; | ||
this.iterations = iterations; | ||
this.type = type; | ||
this.version = version; | ||
} | ||
|
||
/** Hashes the given password. */ | ||
public Argon2Hash hash(String password, byte[] salt) { | ||
Argon2Function instance = Argon2Function.getInstance( | ||
memory, | ||
iterations, | ||
parallelism, | ||
hashLength, | ||
type.toPassword4jType(), | ||
version | ||
); | ||
|
||
Hash hash = Password | ||
.hash(password) | ||
.addSalt(salt) | ||
.with(instance); | ||
|
||
return Argon2EncodingUtils.decode(hash.getResult()); | ||
} | ||
|
||
/** Verifies a password against a hash. */ | ||
public static boolean verify(CharSequence rawPassword, String encodedPassword) { | ||
// decode the `encodedPassword` to get the parameters | ||
Argon2Hash argon2Hash = Argon2EncodingUtils.decode(encodedPassword); | ||
|
||
Argon2Function instance = Argon2Function.getInstance( | ||
argon2Hash.getMemory(), | ||
argon2Hash.getIterations(), | ||
argon2Hash.getParallelism(), | ||
argon2Hash.getHashLength(), | ||
argon2Hash.getType().toPassword4jType(), | ||
argon2Hash.getVersion() | ||
); | ||
|
||
return Password | ||
.check(rawPassword, encodedPassword) | ||
.with(instance); | ||
} | ||
} |
104 changes: 104 additions & 0 deletions
104
java/src/main/java/dev/medzik/libcrypto/Argon2EncodingUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package dev.medzik.libcrypto; | ||
|
||
import java.util.Base64; | ||
|
||
/** | ||
* Utility class for encoding and decoding argon2 hashes. | ||
*/ | ||
public final class Argon2EncodingUtils { | ||
private static final Base64.Encoder b64encoder = Base64.getEncoder().withoutPadding(); | ||
private static final Base64.Decoder b64decoder = Base64.getDecoder(); | ||
|
||
/** | ||
* Encodes the given hash and parameters to a string. | ||
* @param hash hash to encode | ||
* @return encoded hash in argon2 format | ||
*/ | ||
public static String encode(Argon2Hash hash) { | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
switch (hash.getType()) { | ||
case D: | ||
sb.append("$argon2d"); | ||
break; | ||
case I: | ||
sb.append("$argon2i"); | ||
break; | ||
case ID: | ||
sb.append("$argon2id"); | ||
break; | ||
} | ||
|
||
sb.append("$v=").append(hash.getVersion()).append("$m=").append(hash.getMemory()) | ||
.append(",t=").append(hash.getIterations()).append(",p=").append(hash.getParallelism()); | ||
|
||
if (hash.getSalt() != null) { | ||
sb.append("$").append(b64encoder.encodeToString(hash.getSalt())); | ||
} | ||
|
||
sb.append("$").append(b64encoder.encodeToString(hash.getHash())); | ||
return sb.toString(); | ||
} | ||
|
||
/** | ||
* Decodes the given Argon2 encoded hash. | ||
* @param encodedHash encoded hash in argon2 format | ||
* @return {@link Argon2Hash} | ||
*/ | ||
public static Argon2Hash decode(String encodedHash) { | ||
String[] parts = encodedHash.split("\\$"); | ||
if (parts.length < 4) { | ||
throw new IllegalArgumentException("Invalid encoded Argon2-hash"); | ||
} | ||
|
||
int currentPart = 1; | ||
Argon2Type type; | ||
switch (parts[currentPart++]) { | ||
case "argon2d": | ||
type = Argon2Type.D; | ||
break; | ||
case "argon2i": | ||
type = Argon2Type.I; | ||
break; | ||
case "argon2id": | ||
type = Argon2Type.ID; | ||
break; | ||
default: | ||
throw new IllegalArgumentException("Invalid algorithm type: " + parts[0]); | ||
} | ||
|
||
int version; | ||
if (parts[currentPart].startsWith("v=")) { | ||
version = Integer.parseInt(parts[currentPart].substring(2)); | ||
currentPart++; | ||
} else { | ||
throw new IllegalArgumentException("Invalid version parameter"); | ||
} | ||
|
||
String[] performanceParams = parts[currentPart++].split(","); | ||
|
||
if (performanceParams.length != 3) { | ||
throw new IllegalArgumentException("Amount of performance parameters invalid"); | ||
} | ||
|
||
if (!performanceParams[0].startsWith("m=")) { | ||
throw new IllegalArgumentException("Invalid memory parameter"); | ||
} | ||
|
||
int memory = Integer.parseInt(performanceParams[0].substring(2)); | ||
if (!performanceParams[1].startsWith("t=")) { | ||
throw new IllegalArgumentException("Invalid iterations parameter"); | ||
} | ||
|
||
int iterations = Integer.parseInt(performanceParams[1].substring(2)); | ||
if (!performanceParams[2].startsWith("p=")) { | ||
throw new IllegalArgumentException("Invalid parallelity parameter"); | ||
} | ||
|
||
int parallelism = Integer.parseInt(performanceParams[2].substring(2)); | ||
byte[] salt = b64decoder.decode(parts[currentPart++]); | ||
byte[] hash = b64decoder.decode(parts[currentPart]); | ||
|
||
return new Argon2Hash(type, version, memory, iterations, parallelism, salt, hash); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package dev.medzik.libcrypto; | ||
|
||
/** | ||
* Object representation of argon2 hash. | ||
*/ | ||
public final class Argon2Hash { | ||
private final Argon2Type type; | ||
private final int version; | ||
private final int memory; | ||
private final int iterations; | ||
private final int parallelism; | ||
|
||
private final byte[] salt; | ||
private final byte[] hash; | ||
|
||
public Argon2Hash(Argon2Type type, int version, int memory, int iterations, int parallelism, byte[] salt, byte[] hash) { | ||
this.type = type; | ||
this.version = version; | ||
this.memory = memory; | ||
this.iterations = iterations; | ||
this.parallelism = parallelism; | ||
this.salt = salt; | ||
this.hash = hash; | ||
} | ||
|
||
/** Returns the Argon2 type of this hash. */ | ||
public Argon2Type getType() { | ||
return type; | ||
} | ||
|
||
/** Returns argon2 version. */ | ||
public int getVersion() { | ||
return version; | ||
} | ||
|
||
/** Returns memory parameter of this hash. */ | ||
public int getMemory() { | ||
return memory; | ||
} | ||
|
||
/** Returns iteration parameter of this hash. */ | ||
public int getIterations() { | ||
return iterations; | ||
} | ||
|
||
/** Returns parallelism parameter of this hash. */ | ||
public int getParallelism() { | ||
return parallelism; | ||
} | ||
|
||
/** Returns salt of this hash. */ | ||
public byte[] getSalt() { | ||
return salt; | ||
} | ||
|
||
/** Returns hash. */ | ||
public byte[] getHash() { | ||
return hash; | ||
} | ||
|
||
/** Returns the hash length. */ | ||
public int getHashLength() { | ||
return hash.length; | ||
} | ||
|
||
/** Returns hash in encoded format. */ | ||
public String toArgon2String() { | ||
return Argon2EncodingUtils.encode(this); | ||
} | ||
|
||
/** Returns hash in encoded format Same as {@link #toArgon2String()}. */ | ||
@Override | ||
public String toString() { | ||
return toArgon2String(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package dev.medzik.libcrypto; | ||
|
||
import com.password4j.types.Argon2; | ||
|
||
public enum Argon2Type { | ||
D, | ||
I, | ||
ID; | ||
|
||
public Argon2 toPassword4jType() { | ||
switch (this) { | ||
case D: | ||
return Argon2.D; | ||
case I: | ||
return Argon2.I; | ||
case ID: | ||
return Argon2.ID; | ||
default: | ||
throw new IllegalStateException("Unexpected value: " + this); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.