【问题标题】:Decrypting openssl blowfish with Java用Java解密openssl河豚
【发布时间】:2011-12-12 00:53:19
【问题描述】:

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

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

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

对于产生U2FsdGVkX19bSsC3dXTOYssoOK5L3THkhXgiB7X1Trv6SaVO2TGz0g==的输入This is a test.

我正在尝试使用以下代码在 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 不是要使用的正确密码实例。我已经尝试了http://docs.oracle.com/javase/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA 中列出的所有模式和填充组合,但 OAEPWith[digest]And[mgf]Padding 填充不成功。
    • 我注意到,如果我从命令行使用openssl enc -d -blowfish -a -in encrypted.txt 解密文件,密码提示标记为“bf-cbc”,这表明 Blowfish/CBC 而不是 Blowfish/ECB,但是如果我使用它,我会得到java.security.InvalidKeyException: Parameters missing 异常,但我不确定我可以添加什么参数。
  • 命令行中给出的密码应该以某种方式进行转换,否则getBytes("ASCII") 不正确。
  • Java 代码中需要对 salt 进行一些额外的处理。

【问题讨论】:

    标签: java encryption openssl


    【解决方案1】:

    经过大量搜索,我遇到了not-yet-commons-ssl,这似乎提供了一种方法......

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

    当我有时间时,我会深入研究他们的代码,并确切地找出正在做的事情。与此同时,OpenSSL.java 似乎是开始的地方。

    【讨论】:

      【解决方案2】:

      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);
      

      初始化 Cipher 时会提供初始化向量:

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

      这是您所指的缺失参数。

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

      仔细查看上面输出中的加密字符串,即“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 如何格式化编码字符串,以便成功提取盐和正确的密文。

      【讨论】:

      • 感谢 Luke - 这是非常有用的信息,最终将我带到了 juliusdavies.ca/commons-ssl/pbe.html 库,它似乎可以处理我需要做的事情。
      • 酷。很高兴它有帮助,并感谢您的参考。有时我自己可能需要它:)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-29
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      • 2019-03-26
      • 1970-01-01
      相关资源
      最近更新 更多