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

Java 为什么在for循环中检查HashMap是否具有特定值需要很长时间才能执行?,java,performance,hashmap,des,Java,Performance,Hashmap,Des,我正在与双DES的中间相遇攻击一起工作。我已经实现了DES加密/解密并完成了加密,现在我想对双DES执行MITM攻击以找到密钥。我试图实现这一点的方法是,在for循环中,将中间密码存储为HashMap的键,将可能的键存储为HashMap的值。然而,在这个for循环中,我还希望确保可能的键是唯一的,即我有一个if语句,它检查可能的键是否已经存在于HashMap中。如果没有,则使用它加密纯文本,并将密码文本和可能的密钥存储在HashMap中。之后,我尝试通过使用foreach迭代HashMap来查找

我正在与双DES的中间相遇攻击一起工作。我已经实现了DES加密/解密并完成了加密,现在我想对双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++;
    }
}
for(int size=intermediateCipher.size();size
我应该提到,DES密钥只有20位是有效的。这就是为什么有2^20个可能的键。此外,如果我没有if语句(它检查可能的键是否已经在HashMap中),我会得到510个匹配,这太多了

更新:

我尝试先使用一个集合来存储密钥,然后使用集合中的密钥进行加密等。但是,我没有使用for(从0到2^20进行迭代),而是尝试使用while循环,只要集合中有元素,它就会进行迭代检查。然而,我已经尝试运行这种方法超过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++;
            }
        }
for(inti=0;i
我已经读到,对于集合,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);
        }
for(inti=0;i
将有一个线性时间,因为您正在对所有贴图值进行盲目迭代。按照javadoc的方法:

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

要利用哈希查找,您应使用以下方法检查密钥:

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


考虑保留迄今为止存储的密钥的辅助
集,并测试该集中的成员资格,而不是直接测试映射中的值。

如果未使用
temp
,则不需要
toString
,这意味着您不需要解密,也意味着您不需要迭代映射。简言之,JVM非常擅长消除不起任何作用的代码。我认为这是一种幼稚的攻击,其时间大约是宇宙热死亡时间的七倍。“你需要类似于DES的东西。”彼得拉维:你是什么意思?我在下一个if语句中使用了它,或者你是指其他什么吗?@Bab我假设如果你删除了
if
你就删除了
intermediateCipher.containsKey(temp)
,但是同样,没有
if
这个方法调用也没有任何作用。他所说的
if
语句似乎是
if(!intermediateCipher.containsValue(possibleKey))
,并且该密钥不是映射密钥,而是存储为映射值的加密密钥。因此,我应该将我的HashMap更改为,因为可能的密钥现在存储为值?@Bab如果您的查找是主要成本,并且您有足够的我
if (!intermediateCipher.containsKey(possibleKey)) {
  ...
}