为什么检查HashMap是否具有某个值需要很长时间才能在for循环中执行



我正在处理双重DES的中间攻击。我已经实现了DES加密/解密并进行了加密,现在我想对Double DES进行MITM攻击,以找到密钥。我试图实现这一点的方法是在for循环中存储中间密码作为HashMap的密钥,并将可能的密钥存储为HashMap的值。然而,在这个for循环中,我还想确保可能的键是唯一的,即我有一个if语句,它检查可能的键是否已经存在于HashMap中。如果不是,则它使用它来加密纯文本,并将密文和可能的密钥存储在HashMap中。之后,我试图通过用foreach迭代HashMap来找到具有匹配中间密文的密钥,并将加密中的每个中间密文与解密中的中间密文进行比较。

然而,我找不到比赛,因为比赛要花很长时间才能结束。我已经等了2个小时了,但没有任何结果。如果我删除If语句,它会检查可能的密钥是否已经在HashMap中,它将在大约10秒内完成。

for (int size = intermediateCipher.size(); size < Math.pow(2, 20); size++) { // intermediateCipher is my HashMap consisting of <String, byte[]>
byte[] possibleKey = generateDesKey(); // generateDesKey generates a key of 64 bits
if (!intermediateCipher.containsValue(possibleKey)) {
intermediateCipher.put((encrypt(possibleKey, plainText)).toString(), possibleKey);
}
}
int count = 0;
for (Entry<String, byte[]> arr : intermediateCipher.entrySet()) {
String temp = (decrypt(arr.getValue(), cipherText)).toString();
if (intermediateCipher.containsKey(temp)) {
count++;
}
}

我应该指出,DES密钥中只有20位是有效的。这就是为什么有2^20个可能的键。此外,如果我没有if语句来检查可能的密钥是否已经在HashMap中,我会得到510个匹配,这太多了。

更新:

我尝试过使用Set来首先存储密钥,然后使用Set中的密钥进行加密等。但是,我没有使用从0到2^20迭代的for,而是使用while循环,只要Set有元素,就会检查迭代。然而,我已经尝试了这种方法超过10分钟,但没有任何结果。它永远不会脱离循环。

for (int i = 0; i < Math.pow(2, 20); i++) {
possibleKeySet.add(generateDesKey());
}
System.out.println(possibleKeySet.size());
for (int i = 0; i < possibleKeySet.size(); i++) {
intermediateCipher.put((encrypt(possibleKeySet.iterator().next(), plainText)).toString(),
possibleKeySet.iterator().next());
}
System.out.println("ss " + intermediateCipher.size());
int count = 0;
for (Entry<String, byte[]> arr : intermediateCipher.entrySet()) {
String temp = ((decrypt(arr.getValue(), cipherText)).toString());
if (intermediateCipher.containsKey(temp)) {
count++;
}
}

我已经读到,对于一个集合,hasNext((对于一个非空集合总是返回true。因此,我尝试了使用for each,但hashMap的大小与密钥集的大小不同,这对我来说没有意义,因为我使用了密钥集中的每个密钥:

for (int i = 0; i < Math.pow(2, 20); i++) {
possibleKeySet.add(generateDesKey());
}
System.out.println(possibleKeySet.size());
for (byte[] key : possibleKeySet) {
intermediateCipher.put((encrypt(key, plainText)).toString(),
key);
}

Map.containsValue()将有一个线性时间,因为您在所有映射值上盲目迭代。按照方法javadoc:

如果此映射将一个或多个键映射到指定值,则返回true。更正式地说,当且仅当该映射至少包含一个到值v的映射,使得Objects.equals(value,v(时,返回true对于map接口的大多数实现,此操作可能需要映射大小的时间线性

要利用哈希查找,您应该使用Map.containsKey():检查密钥

if (!intermediateCipher.containsKey(possibleKey)) {
...
}

Map.containsValue()必须检查每个映射条目。这在地图的大小上花费了O(n(。假设重复的数量不超过生成的所有密钥的固定分数,则在循环的每次迭代中检查containsValue()会在生成的密钥数量中花费合计O(n2(。花一百万把钥匙,真是太贵了。

相反,考虑保留到目前为止存储的密钥的辅助Set,并在该集中测试成员身份,而不是直接测试Map中的值。

最新更新