Java 以整数作为键和值的HashMap花费的时间太长,无法完成工作

Java 以整数作为键和值的HashMap花费的时间太长,无法完成工作,java,hashmap,Java,Hashmap,我正在为2DES的中间相遇攻击工作。我已经实现了DES加密/解密,它正在工作。我试图实现这一点的方法是,在for循环中,将中间密码存储为HashMap的键,将可能的键存储为HashMap的值。两者都是整数-以字节[]开始,但发现键不能是数组。然而,在这个for循环中,我还想确保可能的键是唯一的,即我有一个while循环,它确保HashMap的大小是2^20,只有DES键的20位是有效的。之后,我尝试通过使用foreach迭代HashMap来查找具有匹配中间密文的密钥,并将加密中的每个中间密文与解

我正在为2DES的中间相遇攻击工作。我已经实现了DES加密/解密,它正在工作。我试图实现这一点的方法是,在for循环中,将中间密码存储为HashMap的键,将可能的键存储为HashMap的值。两者都是整数-以字节[]开始,但发现键不能是数组。然而,在这个for循环中,我还想确保可能的键是唯一的,即我有一个while循环,它确保HashMap的大小是2^20,只有DES键的20位是有效的。之后,我尝试通过使用foreach迭代HashMap来查找具有匹配中间密文的密钥,并将加密中的每个中间密文与解密中的中间密文进行比较

但是,我找不到比赛,因为比赛需要很长时间才能完成。我已经等了20分钟,没有结果

while (intermediateCipher.size() < Math.pow(2, 20)) {
            byte[] key = generateDesKey();

            intermediateCipher.put(ByteBuffer.wrap(encrypt(key, plainText)).getInt() , ByteBuffer.wrap(key).getInt());
        } 

        int count = 0;
        for (Entry<Integer, Integer> arr : intermediateCipher.entrySet()) {
            byte[] k2 = ByteBuffer.allocate(8).putInt(arr.getValue()).array();
            int temp = ByteBuffer.wrap(decrypt(k2, cipherText2)).getInt();
            if (intermediateCipher.containsKey(temp)) {
                count++;
                byte[] k1 = ByteBuffer.allocate(8).putInt(intermediateCipher.get(temp)).array();

                if (encrypt(k2, encrypt(k1, plainText)) == cipherText2) {
                    System.out.println("Key is " + k1 + " " + k2);
                }
            }
        }
中间码是我的HashMap


明文是8字节的字节[],cipherText2是明文上2DES的加密结果,GeneratedSkey是生成64位的方法,其中跳过奇偶校验位以确保20位有效,并将位转换为字节[]由于DES要求

以下是一些您可以尝试缩短运行时间的方法


首先,从HashMap切换到TreeMap。当HashMap变得太大时,如2^20,最坏情况下的搜索将从O1转到On,因为哈希表中的所有插槽都充满了大量条目。然而,树映射搜索总是在Olg n中运行

其次,从地图切换到地图。您只需要将映射键转换为整数;您可以将值保留为字节数组,从而大大减少字节[]->ByteBuffer->int转换

Map<Integer, byte[]> intermediateCipher = new TreeMap<>();


在阅读了您的代码之后,我有几个建议来优化它:

最重要的是:如果您只能访问一次,请不要浪费时间访问地图两次:而不是: 在第二个循环中,可以进行类似的转换

正如@Thilo在一篇评论中所建议的,根据预期的最大尺寸预先调整地图的尺寸始终是一种好的做法。应该是这样的: Map intermediateCipher=new HashMapint1.7d*expectedSize;

循环,而intermediateCipher.size对于int i=0;有什么课程教这种东西吗?前几天我看到了一个非常好的例子,这不是第一次……有几个概念和理解上的错误。1.2DES的输入是一个8字节的数组,其中仅使用7ms字节。2.20分钟算不了什么,试试天++。3.DES密钥只有20位有效,这意味着它是错误的,毫无意义。4.2DES有一个112 but键,但容易受到生日悖论的影响,生日悖论降低了它。@zaph。我的意思是键是64位,但有效位是20位,其余加上零。是的@flakes,是我,但当我调试代码时,我发现我无法使用byte[]和String,因此,我把密钥和值都改成整数。考虑一下,你可以任意地将密钥限制为20位。DES有一个8字节的56位密钥,奇偶校验位现在通常被忽略。当HashMap变得太大(如2^20)时,最坏情况下的搜索预计会从O1变为On,因为哈希表中的所有插槽都充满了大量条目真的吗?难道它不会用更多的桶来重新灰化吗?提前设置预期容量可能是一个好主意,以避免做太多。@Leo Aso,我已经尝试了你的建议,不幸的是,我已经等待了大约20分钟,没有任何结果。我认为这与字节[]->ByteBuffer->int的转换有关。我在int-mapKey=tempBuffer.putencryptkey,plainText.getInt;我做了一些研究,我发现这意味着这个缓冲区中剩余的字节不到8个,但是如何呢?Ups。是我的错。右图:这是因为在每次写入之前必须倒回缓冲区,以确保数据在开头写入,然后在每次读取之前再次倒回缓冲区,以确保数据从开头读取。请参阅第2点和第5点的更新。由于arr.getValue和intermediatePicpher.gettemp是整数,我需要将它们转换为字节[]?已尝试以下操作:byte[]k2=ByteBuffer.allocate8.putIntarr.getValue.array;int temp=ByteBuffer.wrapdecryptk2,cipherText2.getInt;字节[]k1=ByteBuffer.allocate8.PutinIntermediateCipher.gettemp.array;您需要将它们转换为字节[],好的。你用了那些公式。您得到了什么?我在字节[]k1=ByteBuffer.allocate8.PutinIntermediateCipher.gettemp.array上得到了一个nullpointer异常;
while (intermediateCipher.size() < Math.pow(2, 20)) {
    byte[] key = generateDesKey();
    int encrypted = ByteBuffer.wrap(encrypt(key, plainText)).getInt();
    intermediateCipher.put(encrypted, key);
} 

int count = 0;
for (Entry<Integer, byte[]> arr : intermediateCipher.entrySet()) {
    byte[] k2 = arr.getValue();
    int temp = ByteBuffer.wrap(decrypt(k2, cipherText2)).getInt();

    if (intermediateCipher.containsKey(temp)) {
        count++;
        byte[] k1 = intermediateCipher.get(temp);
        if (encrypt(k2, encrypt(k1, plainText)) == cipherText2) {
            System.out.println("Key is " + k1 + " " + k2);
        }
    }
}
if (intermediateCipher.containsKey(temp)) { byte[] k1 = intermediateCipher.get(temp); ... } byte[] k1 = intermediateCipher.get(temp); if (k1!=null) { ... }
ByteBuffer tempBuffer=ByteBuffer.allocate(8);
while (intermediateCipher.size() < Math.pow(2, 20)) {
    // Note: A call to rewind() must be done before each put/get operation on the buffer:
    byte[] key = generateDesKey();
    tempBuffer.rewind();
    tempBuffer.put(encrypt(key, plainText));
    tempBuffer.rewind();
    int mapKey=tempBuffer.getInt();
    tempBuffer.rewind();
    tempBuffer.put(key);
    tempBuffer.rewind();
    int mapValue=tempBuffer.getInt();
    intermediateCipher.put(mapKey, mapValue);
}