用Java解密openssl河豚

时间:2011-12-12 00:53:20

标签: java encryption openssl

我有一个远程系统通过openssl命令行程序向我发送数据,使用blowfish加密。

具体来说,正在运行的命令是:

openssl enc -blowfish -a -salt -in original.txt -out encrypted.txt -pass pass:secret

对于生成This is a test.

的输入U2FsdGVkX19bSsC3dXTOYssoOK5L3THkhXgiB7X1Trv6SaVO2TGz0g==

我正在尝试使用以下代码在Java的另一端解密此内容。

// requires commons-io and commons-codec
public void testDecryption() throws Exception {
    File encryptedFile = new File("encrypted.txt");
    String password = "secret";

    byte[] base64EncryptedBytes = FileUtils.readFileToByteArray(encryptedFile);
    byte[] encryptedBytes = new Base64().decode(base64EncryptedBytes);

    SecretKeySpec blowfishKey = new SecretKeySpec(password.getBytes("ASCII"), "Blowfish");
    Cipher blowfishCipher = Cipher.getInstance("Blowfish/ECB/NoPadding");
    blowfishCipher.init(Cipher.DECRYPT_MODE, blowfishKey);
    byte[] decryptedContent = blowfishCipher.doFinal(encryptedBytes);

    System.out.println(new String(decryptedContent));
}

而不是当前产生的原始消息......

êõïÖ¶M≥ O]¢∞;Z<HVÖ_’˚h‘:O›c=w◊®zÉ9˘

我做错了什么?

一些可能的理论

  • Blowfish / ECB / NoPadding不是正确的cypher实例。我已尝试在http://docs.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA列出的模式和填充的每种组合,但OAEPWith [摘要]和[mgf]填充填充失败。
    • 我注意到如果我使用openssl enc -d -blowfish -a -in encrypted.txt从命令行解密文件,则密码提示被标记为'bf-cbc',这表示Blowfish / CBC而不是Blowfish / ECB,但是如果我使用它我得到java.security.InvalidKeyException: Parameters missing例外,但我不确定我可以添加什么参数。
  • 命令行上给出的密码应以某种方式进行转换,或getBytes("ASCII")不正确。
  • 盐的Java代码中需要一些额外的处理。

2 个答案:

答案 0 :(得分:3)

经过大量的搜索后,我遇到了not-yet-commons-ssl,这似乎提供了一种方法来实现这一目标......

byte[] decrypted = OpenSSL.decrypt("blowfish", password.toCharArray(), base64EncryptedBytes);

当我抽出一些时间时,我会深入研究他们的代码并找出究竟正在做什么。与此同时,OpenSSL.java似乎是开始的地方。

答案 1 :(得分:1)

openssl不直接使用密码“secret”,而是使用它来派生密钥,因此您需要复制密钥派生in Java。如果您在openssl中使用-p参数:

$ openssl enc -blowfish -a -salt -in original.txt  -pass pass:secret -p
salt=FB92391C90CF0EA5
key=C8B918619B0736F95704AD3BD53849EC
iv =6F92FB39C5795434
U2FsdGVkX1/7kjkckM8OpYRWgmNmYzHi8JWYOYpDK5w=

你会看到它打印出(十六进制编码)盐以及初始化向量。在生成密钥时,通常会将盐传递给PBEKeySpec,例如

KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1, 128);

初始化密码时提供初始化向量:

blowfishCipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));

这是您引用的缺失参数。

不幸的是,我不知道openssl在这种情况下使用哪个密钥派生函数,或者在Java中是否直接支持相同的算法。希望其他人可以提供这些信息。使用AES的一个很好的等效示例可以在this question的答案中找到。

仔细查看上面输出中的加密字符串,即“U2FsdGVkX1 / 7kjkckM8OpYRWgmNmYzHi8JWYOYpDK5w =”,如果你对它进行base64解码然后进行hexdump,那么你将得到:

Encrypted bytes: 
0000: 53 61 6C 74 65 64 5F 5F   FB 92 39 1C 90 CF 0E A5  Salted__..9.....
0010: 84 56 82 63 66 63 31 E2   F0 95 98 39 8A 43 2B 9C  .V.cfc1....9.C+.

所以字符串“Salted__”加上盐是前置的。换句话说,您还需要了解openssl如何格式化编码字符串,以便您可以成功提取salt和正确的密文。