我有一个远程系统通过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˘
我做错了什么?
一些可能的理论
openssl enc -d -blowfish -a -in encrypted.txt
从命令行解密文件,则密码提示被标记为'bf-cbc',这表示Blowfish / CBC而不是Blowfish / ECB,但是如果我使用它我得到java.security.InvalidKeyException: Parameters missing
例外,但我不确定我可以添加什么参数。getBytes("ASCII")
不正确。答案 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和正确的密文。