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

时间:2018-11-22 17:48:01

标签: java performance hashmap des

我正在对Double-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中的密钥进行加密等。但是,我尝试使用a来代替从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。因此,我尝试为每个设置a,但是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);
        }

2 个答案:

答案 0 :(得分:1)

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

  

如果此映射将一个或多个键映射到指定值,则返回true。更正式地讲,当且仅当此映射包含至少一个到值v的映射(例如Objects.equals(value,v))时,才返回true。 对于大多数Map界面的实现,此操作可能需要在地图大小中呈线性关系。

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

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

答案 1 :(得分:1)

Map.containsValue()必须检查每个地图条目。在地图大小上花费O(n)。假设重复项的数量不超过生成的所有键的固定分数,则在循环的每次迭代中检查containsValue(),然后在键数上的总和为O(n 2 )产生。一百万个键真是太贵了。

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