import java.nio.charset.StandardCharsets;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/** BCrypt only reads the first 72 bytes of the password. Demonstrates what that means. */
public class Bcrypt72ByteTrap {

    public static void main(String[] args) {
        BCryptPasswordEncoder enc = new BCryptPasswordEncoder(10);

        String base = "A".repeat(72);
        String hash = enc.encode(base);
        System.out.println("72-byte password hashes fine: " + enc.matches(base, hash));

        String longer = base + "-and-anything-else-the-attacker-guesses";
        try {
            String h2 = enc.encode(longer);
            System.out.println("encode(>72 bytes) accepted; matches(72-byte prefix)=" + enc.matches(base, h2));
        } catch (IllegalArgumentException e) {
            System.out.println("encode(>72 bytes) rejected: " + e.getMessage());
        }
        try {
            System.out.println("matches(>72 bytes against 72-byte hash)=" + enc.matches(longer, hash));
        } catch (IllegalArgumentException e) {
            System.out.println("matches(>72 bytes) rejected: " + e.getMessage());
        }

        // the multibyte twist: the limit is BYTES, not characters
        String emoji = "🔑".repeat(19); // 19 key emoji: 38 UTF-16 chars, 76 UTF-8 bytes
        System.out.println("emoji password: chars=" + emoji.length() + " utf8-bytes=" + emoji.getBytes(StandardCharsets.UTF_8).length);
        try {
            enc.encode(emoji);
            System.out.println("emoji password accepted");
        } catch (IllegalArgumentException e) {
            System.out.println("emoji password rejected: " + e.getMessage());
        }
    }
}
