package net.rustnotmc.auth; import java.security.SecureRandom; /** * The one source of unpredictable bytes in the project. * * {@link java.util.Random} is seeded from the clock, so anyone who can guess * when a process started can predict every value it will ever produce. That is * fine for a shuffle and fatal for a session token, a salt and a challenge. */ public final class Secure { private static final SecureRandom RANDOM = new SecureRandom(); private Secure() { } public static byte[] bytes(int count) { if (count < 0) { throw new IllegalArgumentException("negative length: " + count); } byte[] value = new byte[count]; RANDOM.nextBytes(value); return value; } public static int nextInt(int bound) { if (bound <= 0) { throw new IllegalArgumentException("bound must be positive: " + bound); } return RANDOM.nextInt(bound); } /** * Compares two byte arrays without a shortcut for the first mismatch. * * An array comparison that returns as soon as it sees a difference reports * how far it got, and an attacker can use that to learn a token one byte at * a time by measuring how long the answer took. */ public static boolean same(byte[] a, byte[] b) { if (a == null || b == null || a.length != b.length) { return false; } int diff = 0; for (int i = 0; i < a.length; i++) { diff |= a[i] ^ b[i]; } return diff == 0; } }