我試圖在 JAVA 中為學校專案創建一個蠻力方法,該方法將生成隨機密鑰并嘗試解密字串。我的方法是將字串作為字母表并在偽代碼中定義長度
final String alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
List<String> getPossibleKeys(String alphabet, Integer keyLength){
...
}
void decrypt(Integer keyLength, String encryptedText){
List<String> keysArray = getPossibleKeys(alphabet, keyLength);
for(String key: keysArray){
out.print(doDecryption(encryptedText,key));
}
}
我的問題是我不知道如何處理 getPossibleKeys 方法。
例如,假設密鑰是“MARIA”,所以它的長度為 5。我希望能夠呼叫getPossibleKeys(alphabet, keyLength)并輸出
MFTER
PWYTS
GFTGB
...
瑪麗亞
...
芬德夫
YJVGN
CVBCV
換句話說,來自提供的字母表的精確長度為 5 的所有可能組合。
我發現的示例使用了字母表中的所有字母,因此我可以使用它們并只保留我想要的長度,但我想還有比這更好的方法。
uj5u.com熱心網友回復:
你真的不應該想一次性生成所有的鍵,因為這會創建一個巨大的表,它甚至可能不適合記憶體。以這種方式耗盡記憶體的速度令人驚訝。
更好和更合適的方法是將整數映射到每個密碼。完成后,您可以簡單地遍歷所有整數直到最大大小,然后呼叫映射函式。
對于密碼(密鑰通常是二進制的),每個密碼由每個位置的字母組成。因此,您可以為 5 個字母的密碼創建一個從 0 到 26^5 的索引(假設您的字母表還包含一個J;))。
那么如何創建密碼呢?嗯,這比你想象的要容易。請注意,計算機是二進制的,我們以十進制計算。因此,計算機已經能夠從基數 2 轉換為基數 10。類似地,您也可以轉換為基數 26。這稱為“基數轉換”,會發生您所說的情況,例如Long.toString(long i, int radix)。
執行基本轉換的方法是簡單地將一個值除以字母表的大小,并將余數用作字母表的索引,對每個字符重復該程序。當然,在 Java 中,除法和余數是單獨的操作(BigInteger只有一個函式,因為這樣更有效,但對于這么小的數字,這不是問題)。
public static String createPassword(int size, String alphabet, long value) {
int n = alphabet.length();
StringBuilder password = new StringBuilder(size);
long changingValue = value;
for (int i = 0; i < size; i ) {
int charIndex = (int) (changingValue % n);
char charInAlphabet = alphabet.charAt(charIndex);
password.append(charInAlphabet);
changingValue /= n;
}
return password.toString();
}
我將由您來計算上面給出的最大尺寸。如果您在最大大小上執行 log_2,那么您將獲得密碼提供的安全級別(有點超過 23 位,這應該很容易暴力破解)。
uj5u.com熱心網友回復:
可以使用遞回方法生成結果串列,其中每個字串項由前綴組成,直到達到長度:
static List<String> getPossibleKeys(alphabet, keyLength) {
return getPossibleKeys(alphabet, new ArrayList<>, "", keyLength);
}
private static List<String> getPossibleKeys(
String alphabet, List<String> acc, String prefix, int keyLength
) {
if (keyLength == 0) {
acc.add(prefix); // key is ready, add to the result
} else {
for (char c : alphabet.toCharArray()) {
getPossibleKeys(alphabet, acc, prefix c, keyLength - 1);
}
}
return acc;
}
測驗(對于較短的字母和長度):
System.out.println(getPossibleKeys("ABC", 2));
System.out.println(buildK("AB", 3));
輸出:
[AA, AB, AC, BA, BB, BC, CA, CB, CC]
[AAA, AAB, ABA, ABB, BAA, BAB, BBA, BBB]
類似于 Maarten Bodewes 的答案的類似迭代解決方案:
- 可能的鍵數是N K,其中N - 字母的長度,K是鍵的長度
- 使用 char 陣列將每個數值轉換為字串,其中數字替換為輸入字母表適當索引處的字符:
static List<String> getPossibleKeys(String abc, int len) {
int sz = abc.length();
int num = (int) Math.pow(sz, len);
List<String> result = new ArrayList<>();
char[] key = new char[len];
for (int i = 0; i < num; i ) {
for (int j = len, n = i; j-- > 0; ) {
key[j] = abc.charAt(n % sz);
n /= sz;
}
result.add(new String(key));
}
return result;
}
System.out.println(getPossibleKeys("KLMN", 2));
// -> [KK, KL, KM, KN, LK, LL, LM, LN, MK, ML, MM, MN, NK, NL, NM, NN]
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/409389.html
標籤:
上一篇:在單個串列中比較字串的最有效方法
