1
+ package PasswordEvaluator ;
2
+
3
+ import java .io .*;
4
+ import java .net .URI ;
5
+ import java .net .http .HttpClient ;
6
+ import java .net .http .HttpRequest ;
7
+ import java .net .http .HttpResponse ;
8
+ import java .util .Random ;
9
+
10
+ /**
11
+ * A utility class for evaluating the strength of passwords
12
+ * and suggesting new secure passwords if needed.
13
+ */
14
+ public class PasswordStrengthEvaluator {
15
+
16
+ private static final String LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
17
+
18
+ /**
19
+ * Evaluates the strength of a given password based on multiple criteria:
20
+ * - Length between 8 and 30 characters
21
+ * - Contains both uppercase and lowercase letters
22
+ * - Contains special characters (@, &, !)
23
+ * - Is not a common password from a predefined list
24
+ *
25
+ * @param password the password to evaluate
26
+ * @return a string representing the strength level (MAX, MIN, COMMON)
27
+ * @throws IOException if there is a problem reading the common passwords file
28
+ */
29
+ public static String evaluatePassword (String password ) throws IOException {
30
+
31
+ boolean hasUppercase = password .matches (".*[A-Z].*" );
32
+ boolean hasLowercase = password .matches (".*[a-z].*" );
33
+ boolean hasSpecialChar = password .contains ("@" ) || password .contains ("&" ) || password .contains ("!" );
34
+ int length = password .length ();
35
+
36
+ boolean isCommon = isCommon (password );
37
+
38
+ if (!isCommon && length >= 8 && length < 30 && hasUppercase && hasLowercase && hasSpecialChar ) {
39
+ return "Password strength level: MAX" ;
40
+ }
41
+
42
+ if (length < 8 || !hasUppercase || !hasLowercase || !hasSpecialChar || length >= 30 ) {
43
+ suggetsPassword (12 );
44
+ return "Password strength level: MIN" ;
45
+ }
46
+
47
+ if (isCommon ) {
48
+ return "Password strength level: COMMON" + suggetsPassword (12 );
49
+ }
50
+
51
+ return "Unable to determine password strength." ;
52
+ }
53
+
54
+
55
+ /**
56
+ * Checks whether a given password appears in a list of the most common passwords,
57
+ * retrieved from a remote public file on GitHub. The comparison is exact, line by line.
58
+ *
59
+ * @param password the password to check
60
+ * @return true if the password is exactly matched in the list, false otherwise
61
+ * @throws RuntimeException if there is an error reading the remote password file
62
+ */
63
+ public static boolean isCommon (String password ) {
64
+ String fileUrl = "https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/10-million-password-list-top-1000000.txt" ;
65
+
66
+ try {
67
+ HttpClient client = HttpClient .newHttpClient ();
68
+ HttpRequest request = HttpRequest .newBuilder ()
69
+ .uri (URI .create (fileUrl ))
70
+ .build ();
71
+
72
+ HttpResponse <InputStream > response = client .send (request , HttpResponse .BodyHandlers .ofInputStream ());
73
+
74
+ try (BufferedReader reader = new BufferedReader (new InputStreamReader (response .body ()))) {
75
+ String line ;
76
+ while ((line = reader .readLine ()) != null ) {
77
+ if (line .equals (password )) {
78
+ return true ;
79
+ }
80
+ }
81
+ }
82
+
83
+ } catch (Exception e ) {
84
+ throw new RuntimeException ("Error reading the common passwords file." , e );
85
+ }
86
+
87
+ return false ;
88
+ }
89
+
90
+
91
+
92
+
93
+
94
+ /**
95
+ * Suggests a secure random password of a specified length,
96
+ * containing only uppercase and lowercase letters.
97
+ *
98
+ * If the requested length is less than 8, a password with 8 characters is suggested
99
+ * and a warning message is returned.
100
+ *
101
+ * @param length the desired length of the suggested password
102
+ * @return a suggested password or a warning message if the length is too short
103
+ */
104
+ private static String suggetsPassword (int length ) {
105
+ Random random = new Random ();
106
+ StringBuilder password = new StringBuilder ();
107
+ StringBuilder provisionallyPassword = new StringBuilder ();
108
+
109
+ if (length >= 8 ) {
110
+ for (int i = 0 ; i < length ; i ++) {
111
+ int index = random .nextInt (LETTERS .length ());
112
+ password .append (LETTERS .charAt (index ));
113
+ }
114
+ return password .toString ();
115
+ } else {
116
+ for (int i = 0 ; i < 8 ; i ++) {
117
+ int index = random .nextInt (LETTERS .length ());
118
+ provisionallyPassword .append (LETTERS .charAt (index ));
119
+ }
120
+ return "Length must be between 8 and 30 characters. Suggested password with 8 characters: " + provisionallyPassword .toString ();
121
+ }
122
+ }
123
+ }
0 commit comments