feat(4): task 2b
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
*.pdf
|
*.pdf
|
||||||
sheet01/a2/Hash.java
|
sheet01/a2/Hash.java
|
||||||
*.class
|
*.class
|
||||||
|
passwd
|
||||||
|
|||||||
149
sheet04/a2/AuthWithTOTP.java
Normal file
149
sheet04/a2/AuthWithTOTP.java
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.HexFormat;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.crypto.Mac;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
public class AuthWithTOTP {
|
||||||
|
|
||||||
|
private static final byte[] INVALID_HASH =
|
||||||
|
"----------------------------------------------------------------".getBytes();
|
||||||
|
|
||||||
|
// hex-encoded: 3c2bc45f2de6568bb285aa1c6fcac1b6965cc770
|
||||||
|
// base32-encoded: HQV4IXZN4ZLIXMUFVIOG7SWBW2LFZR3Q
|
||||||
|
private static final byte[] K = new byte[] {
|
||||||
|
60,
|
||||||
|
43,
|
||||||
|
-60,
|
||||||
|
95,
|
||||||
|
45,
|
||||||
|
-26,
|
||||||
|
86,
|
||||||
|
-117,
|
||||||
|
-78,
|
||||||
|
-123,
|
||||||
|
-86,
|
||||||
|
28,
|
||||||
|
111,
|
||||||
|
-54,
|
||||||
|
-63,
|
||||||
|
-74,
|
||||||
|
-106,
|
||||||
|
92,
|
||||||
|
-57,
|
||||||
|
112,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// I changed it to a scanner cause my terminal had issues with the other thingy
|
||||||
|
try (Scanner sc = new Scanner(System.in)) {
|
||||||
|
Map<String, byte[]> passwd = Files.readAllLines(Path.of("passwd"))
|
||||||
|
.stream()
|
||||||
|
.filter(line -> line.indexOf(":") > 1 && line.length() > 3)
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(
|
||||||
|
line -> line.substring(0, line.indexOf(':')),
|
||||||
|
line ->
|
||||||
|
HexFormat.of().parseHex(
|
||||||
|
line.substring(line.indexOf(':') + 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
System.out.println(
|
||||||
|
"Chocolate Factory SCADA Command Line Interface v2.2.144"
|
||||||
|
);
|
||||||
|
System.out.println();
|
||||||
|
System.out.println(
|
||||||
|
"Please, enter your authentication credentials."
|
||||||
|
);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
String username;
|
||||||
|
String password;
|
||||||
|
String totpCode;
|
||||||
|
|
||||||
|
long timeout = 500;
|
||||||
|
while (true) {
|
||||||
|
System.out.print("> Username: ");
|
||||||
|
username = sc.nextLine();
|
||||||
|
System.out.print("> Password: ");
|
||||||
|
password = sc.nextLine();
|
||||||
|
System.out.print("> TOTP Code: ");
|
||||||
|
totpCode = sc.nextLine();
|
||||||
|
|
||||||
|
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||||
|
byte[] encodedHash = digest.digest(password.getBytes());
|
||||||
|
|
||||||
|
// constant time comparison to prevent timing attacks
|
||||||
|
if (
|
||||||
|
MessageDigest.isEqual(
|
||||||
|
passwd.getOrDefault(username, INVALID_HASH),
|
||||||
|
encodedHash
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Get the counter from the unix seconds
|
||||||
|
final var counter = (int) Math.floor(
|
||||||
|
Instant.now().getEpochSecond() / 30.0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Compute the hmac
|
||||||
|
final var mac = Mac.getInstance("HmacSHA1");
|
||||||
|
mac.init(new SecretKeySpec(K, "HmacSHA1"));
|
||||||
|
mac.update(ByteBuffer.allocate(8).putLong(counter).array());
|
||||||
|
final var hmacResult = mac.doFinal();
|
||||||
|
|
||||||
|
// Do the truncating + modulo
|
||||||
|
int offset = hmacResult[19] & 0x0f;
|
||||||
|
int binaryCode =
|
||||||
|
((hmacResult[offset] & 0x7f) << 24) |
|
||||||
|
((hmacResult[offset + 1] & 0xff) << 16) |
|
||||||
|
((hmacResult[offset + 2] & 0xff) << 8) |
|
||||||
|
(hmacResult[offset + 3] & 0xff);
|
||||||
|
binaryCode = binaryCode % 1000000;
|
||||||
|
|
||||||
|
// Validate the code + padding
|
||||||
|
final var code = String.format("%06d", binaryCode);
|
||||||
|
if (!code.equals(totpCode)) {
|
||||||
|
System.out.println(
|
||||||
|
"Invalid username, password and/or TOTP code."
|
||||||
|
);
|
||||||
|
Thread.sleep(timeout);
|
||||||
|
timeout *= 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.printf("Welcome %s!%n", username);
|
||||||
|
Thread.sleep(150);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// exponential timeout to prevent brute force attacks
|
||||||
|
System.out.println(
|
||||||
|
"Invalid username, password and/or TOTP code."
|
||||||
|
);
|
||||||
|
Thread.sleep(timeout);
|
||||||
|
timeout *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printSystemStatus();
|
||||||
|
printSecretRecipe();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printSystemStatus() throws Exception {
|
||||||
|
// SECRET
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printSecretRecipe() throws Exception {
|
||||||
|
// SECRET
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user