3

我在stackoverflow中找到了一个链接use-3des-encryption-decryption-in-java,但实际上该方法只使用了两个参数:HG58YZ3CR9”和“ IvParameterSpec iv = new IvParameterSpec(new byte[8]);
但是三重des最强大的选项可以使用三个不同的密钥来加密消息。那么怎么做呢?我在 Cipher 中找到了一个方法,它使用“SecureRandom”作为另一个参数。那么这是正确的方法吗?
第一个方法代码如下:

import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class TripleDESTest {

    public static void main(String[] args) throws Exception {

        String text = "kyle boon";

        byte[] codedtext = new TripleDESTest().encrypt(text);
        String decodedtext = new TripleDESTest().decrypt(codedtext);

        System.out.println(codedtext); // this is a byte array, you'll just see a reference to an array
        System.out.println(decodedtext); // This correctly shows "kyle boon"
    }

    public byte[] encrypt(String message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("SHA-1");
        final byte[] digestOfPassword = md.digest("HG58YZ3CR9"
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);

        final byte[] plainTextBytes = message.getBytes("utf-8");
        final byte[] cipherText = cipher.doFinal(plainTextBytes);
        // final String encodedCipherText = new sun.misc.BASE64Encoder()
        // .encode(cipherText);

        return cipherText;
    }

    public String decrypt(byte[] message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("SHA-1");
        final byte[] digestOfPassword = md.digest("HG58YZ3CR9"
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        decipher.init(Cipher.DECRYPT_MODE, key, iv);

        // final byte[] encData = new
        // sun.misc.BASE64Decoder().decodeBuffer(message);
        final byte[] plainText = decipher.doFinal(message);

        return new String(plainText, "UTF-8");
    }
}
4

2 回答 2

2

根据本文档,只需向密码传递一个 168 位长的密钥。

密钥大小必须等于 112 或 168。

密钥大小为 112 将生成具有 2 个中间密钥的三重 DES 密钥,密钥大小为 168 将生成具有 3 个中间密钥的三重 DES 密钥。

您的代码似乎做了一些有问题的事情来弥补 MD5 的输出只有 128 位长这一事实。

从互联网上复制粘贴密码代码不会产生安全的应用程序。使用静态 IV 会影响 CBC 模式优于 ECB 的几个原因。如果您使用的是静态密钥,您可能应该考虑使用安全随机数生成器生成随机字节,而不是从短 ASCII 字符串派生密钥。此外,绝对没有理由在新应用程序中使用 Triple DES 代替 AES。

于 2013-07-04T11:02:42.977 回答
0

原则上,生成 DES ABA 密钥的 for-next 循环似乎是正确的。请注意,您可以为 DESede 提供从 Java 7 开始的 16 字节密钥,这相当于同一件事

也就是说,您展示的代码还有很多不足之处:

我不安全:

  • 密钥不是由基于密码的密钥派生函数 (PBKDF) 使用(密码?)字符串生成的
  • 密钥由两个而不是三个组成(使用带 ABA 密钥的三重 DES 或 TDEA)
  • IV 设置为全零而不是随机的
  • “密码”字符串太短

此外,可以看到以下代码错误:

  • 使用new sun.misc.BASE64Encoder()Sun 专有软件包中的 which(可以在运行时的任何升级过程中删除或更改)
  • 抛出Exception平台异常和运行时异常(无法解密与无法实例化的处理方式相同Cipher
  • 在调用中请求 24 个字节而不是 16 个Arrays.copyOf()(这似乎返回 24 个 SHA-1 输出,而只有 20 个字节)

要从密码(类似)字符串生成 3DES 24 字节(使用 168 位)DES ABC 密钥,您应该使用 PBKDF-2。如果中间人攻击或填充预言适用,添加身份验证标签也非常重要。如果您也可以控制正在使用的算法,那么升级到 AES 会更加安全和实用。

于 2013-07-05T23:25:27.503 回答