feat(4): task 2b

This commit is contained in:
Unbreathable
2026-05-15 10:11:42 +02:00
parent 64ae54469d
commit 62fb088403
2 changed files with 151 additions and 1 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.pdf
sheet01/a2/Hash.java
*.class
*.class
passwd

View 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
}
}