feat(4): task 2b
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
*.pdf
|
||||
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