Java 3DES的手动实现(学术)

Java 3DES的手动实现(学术),java,cryptography,3des,Java,Cryptography,3des,对于我正在学习的一门课程,我们正在手动实现3DES方案,这在纸上非常简单(双密钥,带有EDE加密)。我选择Java作为实现语言,但遇到了一个问题,即它如何处理不同密钥的加密/解密。在尝试应用第二轮时,我一直收到一个javax.crypto.BadPaddingException错误(即K2的“解密”)。默认DES密码使用PKCS5Padding,我假设这就是问题所在,但我不确定如何解决它。下面是我的加密代码(我希望它不是太直截了当,更不要说我忽略了一些简单的东西)。先谢谢你 关键定义(非常基本,

对于我正在学习的一门课程,我们正在手动实现3DES方案,这在纸上非常简单(双密钥,带有EDE加密)。我选择Java作为实现语言,但遇到了一个问题,即它如何处理不同密钥的加密/解密。在尝试应用第二轮时,我一直收到一个javax.crypto.BadPaddingException错误(即K2的“解密”)。默认DES密码使用PKCS5Padding,我假设这就是问题所在,但我不确定如何解决它。下面是我的加密代码(我希望它不是太直截了当,更不要说我忽略了一些简单的东西)。先谢谢你

关键定义(非常基本,我会在浏览时看到一些不同的方法,所以我会改进它)


问题是,您不应该在第二步(解密)和第三步(加密)中使用任何填充。实际应用
EDE
时,应仅填充纯文本

转换的形式如下:

“算法/模式/填充”或“算法”(在后一种情况下, 模式和填充方案的特定于提供程序的默认值为 使用)

因此,您应该明确告诉它不要在cipher2和cipher3上使用填充(您还没有创建后者)

因此,您应该有三个密码对象:

  • 密码1 DES/ECB/PKCS5P
  • 密码2 DES/ECB/NOP
  • 密码3 DES/ECB/NOP
[额外提示]


对于解密,您应该以不同的方式初始化密码,还应该对密码重新排序。

好问题;您可能需要添加spec_1和spec_2,我认为doFinal的操作可能取决于spec。您可以添加吗?如何创建cipher和cipher2?您不必担心这一点,因为第一次加密应该适当地填充输出;那么,这段代码是否仍然有效?是的,从我所看到的情况来看,首字母E将进行正确的填充。我刚刚使用了小字符串(即“test”),它正确地从4字节填充到8字节。OP遇到了第二步的问题-即解密。如果未正确初始化(使用填充),则加密引擎会在解密后尝试删除填充,但会失败,因为解密密钥与加密密钥不同(我们假设)。使用EDE填充的纯文本仅使用一次,填充长度为8个字符(字节)的倍数。如果
密码
是cipher.getInstance(“DES/PKCS5Padding”)的实例,则不应使用它执行第三步,因为中间结果将再次被填充
        KeyGenerator kgen = KeyGenerator.getInstance("DES");
        SecretKey sk_1 = kgen.generateKey(); 
        SecretKey sk_2 = kgen.generateKey();
        byte[] raw_1 = sk_1.getEncoded();
        byte[] raw_2 = sk_2.getEncoded();

        spec_1 = new SecretKeySpec(raw_1, "DES"); //key 1
        spec_2 = new SecretKeySpec(raw_2, "DES"); //key 2

        cipher = Cipher.getInstance("DES"); //standard mode is ECB which is block-by-block w/PKCS5Padding
        cipher2 = Cipher.getInstance("DES");


    protected byte[] get3DESEncryption(byte[] plaintext) throws Exception{
        byte[] output = new byte[plaintext.length];
        System.out.println("output len init: " + output.length);
        cipher.init(Cipher.ENCRYPT_MODE, spec_1);
        cipher2.init(Cipher.DECRYPT_MODE, spec_2);

        //first encryption round, key 1 used
        output = cipher.doFinal(plaintext);
        //second "encryption" round, key 2 used but decrypt run
        output = cipher2.doFinal(output);
        //third encryption round, key 1 used
        output = cipher.doFinal(output);

        //return ciphertext
        return output;
    }