下面的代码循环遍历所有提交的字符,将它们放入字符串数组,然后对它们进行哈希处理,然后对最初输入的哈希密码进行检查。此逻辑适用于最多5个字符的密码,但是当我输入6个字符时,排列数(36 ^ 6)太大,以至于由于数组的大小太大而引发了内存异常。
因此,我也试图仅使用字符串而不是数组来修改它来停止此内存问题,但无法完全正常工作,有任何明显的建议吗?
答案 0 :(得分:1)
您只需列举从0到无穷大并以36为底的数字toString
即可枚举所有可能的包含字母和数字的密码。
long k = 0;
while (true) {
String pwd = Long.toString(k++, 36);
if (SHA1(pwd).equals(hashedPassword)) {
System.out.println(pwd);
}
}
在这里,toString
使用[0-9a-z]
最多可使用36个基数,也就是说,它适用于您的情况,但是如果要包括特殊字符,则必须创建自己的数字, -password功能(考虑除法和取模),其余部分保持不变。
这样,内存要求是O(1),但是对于最多n个字符的密码,复杂度当然仍然是O(36 n )。
此方法的一个问题是-与所有数字表示一样,前导零将被省略,因此Long.toString
将永远不会产生以0
开头的密码({{1}除外) }本身)。为了解决这个问题,您可以使用两个嵌套循环-外循环迭代密码中的数字位数,内循环迭代数字直至36 d 并将字符串填充前导零,或者从36 d 循环到2 * 36 d ,并切掉第一个(非零)数字。这似乎比以前需要做更多的工作,但实际上它只产生两倍的密码。
0
输出:
for (int d = 1; d < 3; d++) {
long p = pow(36, d);
for (long n = p; n < 2 * p; n++) {
String pwd = Long.toString(n, 36).substring(1);
System.out.println(n + " " + pwd);
}
}
答案 1 :(得分:0)
除了tobias的答案。
这是一种您可以使用指定字母遍历它的所有可能组合(直到一定长度)并对其进行操作而无需存储它们的一种方法,除非您检测到它是一个匹配。
// Depth first combinations
private static void combineRecurse(String base, char[] alphabet, int maxLen,
Consumer<String> consumer) {
if (base.length() < maxLen - 1) {
for (int i = 0; i < alphabet.length; i++) {
String newPermutation = base + alphabet[i];
consumer.accept(newPermutation);
combineRecurse(newPermutation, alphabet, maxLen, consumer);
}
} else {
// the new permutiation will be the maxlength
for (int i = 0; i < alphabet.length; i++) {
consumer.accept(base + alphabet[i]);
}
}
}
public static void forEachCombination(char[] alphabet, int maxLen, Consumer<String> consumer) {
if(alphabet == null || consumer == null || maxLen < 1) return;
combineRecurse("", alphabet, maxLen, consumer);
}
public static void main(String[] args) {
char[] alphabet = { ... };
final String hashedPassword = SHA1(password);
final int maxlen = 16;
List<String> possiblePasswords = new ArrayList<>();
forEachCombination(alphabet, maxlen, s -> {
// System.out.println(s);
if (SHA1(s).equals(hashedPassword)) {
possiblePasswords.add(s);
}
});
}
进行这种迭代而不是递归可能会更好,但是现在递归易于实现,并且对于初学者来说更容易理解。