openssl des3在java中解密

时间:2009-04-17 09:25:39

标签: java

有没有办法解密使用加密的文件 openssl -des3 enc命令。 究竟openssl如何使用密码和盐来制作密钥?

2 个答案:

答案 0 :(得分:5)

OpenSSL的enc实用程序对密码使用非标准(和低质量)密钥派生算法。以下代码显示了enc实用程序如何生成密钥和初始化向量,给定salt和密码。请注意,enc在指定-salt选项时将“salt”值存储在加密文件中(这对安全性至关重要)。

public InputStream decrypt(InputStream is, byte[] password)
  throws GeneralSecurityException, IOException
{
  /* Parse the "salt" value from the stream. */
  byte[] header = new byte[16];
  for (int idx = 0; idx < header.length;) {
    int n = is.read(header, idx, header.length - idx);
    if (n < 0)
      throw new EOFException("File header truncated.");
    idx += n;
  }
  String magic = new String(header, 0, 8, "US-ASCII");
  if (!"Salted__".equals(magic))
    throw new IOException("Expected salt in header.");

  /* Compute the key and IV with OpenSSL's non-standard method. */
  SecretKey secret;
  IvParameterSpec iv;
  byte[] digest = new byte[32];
  try {
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    md5.update(password);
    md5.update(header, 8, 8);
    md5.digest(digest, 0, 16);
    md5.update(digest, 0, 16);
    md5.update(password);
    md5.update(header, 8, 8);
    md5.digest(digest, 16, 16);
    iv = new IvParameterSpec(digest, 24, 8);
    DESedeKeySpec keySpec = new DESedeKeySpec(digest);
    SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
    secret = factory.generateSecret(keySpec);
  }
  finally {
    Arrays.fill(digest, (byte) 0);
  }

  /* Initialize the cipher. */
  Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
  cipher.init(Cipher.DECRYPT_MODE, secret, iv);
  return new CipherInputStream(is, cipher);
}

EVP_BytesToKey(3) documentation. enc命令使用1作为迭代count来描述此密钥和IV生成(这是一个坏主意,并注明为错误在我的enc版本的手册页中,MD5作为摘要算法 - 一个“破碎”的算法。

目前尚不清楚OpenSSL如何将文本密码转换为字节。我猜它使用默认的平台字符编码。因此,如果您遇到String密码(不好,因为它不能“零化”),您只需致电password.getBytes()将其转换为byte[]

如果可以,请使用Java 6的Console或Swing的JPasswordField之类的密码来获取密码。这些返回一个数组,因此您可以在完成后从内存中“删除”密码:Arrays.fill(password, '\0');

答案 1 :(得分:1)

谢谢你,埃里克森,你的帖子。它帮助我极大地尝试重新创建openssl的密码和IV例程。

我的结果略有不同,可能是因为我需要解密blowfish加密数据而不是DES。见下文。

此外,我发现openssl在遇到字节00,0a或0d时将停止读取密码。通常我认为openssl只读取字节11和127之间的密码字符。因此,对于下面的示例,我的代码在此之前截断密码,如果它包含00,0a或0d。

     /* Compute the key and IV with OpenSSL's non-standard method. */
     final byte[] digest = new byte[32];
     final MessageDigest md5 = MessageDigest.getInstance("MD5");
     md5.update(password, 0);
     // append the salt
     md5.update(salt);
     // run the digest and output 16 bytes to the first 16 bytes to the digest array. Digest is reset
     md5.digest(digest, 0, 16);
     // write the first 16 bytes from the digest array back to the buffer
     md5.update(digest, 0, 16);
     // append the password
     md5.update(password, 0);
     // append the salt
     md5.update(salt);
     // run the digest and output 16 bytes to the last 16 bytes of the digest array
     md5.digest(digest, 16, 16);
     key = Arrays.copyOfRange(digest, 0, 16);
     iv = Arrays.copyOfRange(digest, 16, 24);

上面的代码可以使用org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator替换为3行。它变成

final OpenSSLPBEParametersGenerator generator = new OpenSSLPBEParametersGenerator();
generator.init(password, salt);
final ParametersWithIV ivParam = (ParametersWithIV)generator.generateDerivedParameters(16, 8);
final KeyParameter keyParameter = (KeyParameter)ivParam.getParameters();