Blowfish 在 Java/Scala 中加密并在 bash 中解密
Blowfish encrypt in Java/Scala and decrypt in bash
我正在尝试构建一个工具来解密在 Scala 应用程序中加密的 bash 中的内容:
但首先,我必须成功地用两种语言编码相同的消息并使它们相等:
给定密码“0123456789abcdef”
(十六进制:“30313233343536373839616263646566”和字节[]:[48、49、50、51、52、53、54、55、56、57、97, 98、99、100、101、102])
scala> import javax.crypto.Cipher
scala> import javax.crypto.spec.SecretKeySpec
scala> val cipher = Cipher.getInstance("Blowfish")
scala> cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("0123456789abcdef".getBytes("utf-8"), "Blowfish"))
scala> javax.xml.bind.DatatypeConverter.printBase64Binary(cipher.doFinal("message".getBytes("utf-8")))
res7: String = K679Jz06jmc=
但我无法在 bash 中使用 openssl
重现相同的内容。
$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "0123456789abcdef"
LJ3iFJ2/mYk=
$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "30313233343536373839616263646566"
JkkJgYv3fQg=
有什么提示吗?
谢谢!
标记 OpenSSL 会更准确,它在任何 shell 或根本没有 shell 时都运行相同。
OpenSSL enc
默认情况下进行 基于密码的 加密,密钥(加上 IV)推导类似于(但不完全)PBKDF1。要使用 密钥 而不是密码进行加密,您需要使用带十六进制的大写 -K
,并且至少需要指定 -iv
的一部分;另一方面 -nosalt
没用。
此外,echo
命令在它回显的数据中添加了一个换行符,'m e s s a g e NL'的加密与[=48=的加密完全不同].某些操作系统和 shells,取决于您使用的 echo
是内置的还是外部的,有办法省略换行符,但它们并不完全相同。 OTOH 所有 POSIX 系统都支持 printf
,因此:
$ printf %s message | openssl enc -blowfish -K 30313233343536373839616263646566 -iv 00 -a
K679Jz06jmc=
编辑:Artjom 是正确的; Java/Scala(可能)默认为 ECB,这是一个坏主意;您应该指定 /CBC
或 /CTR
和填充。与 aventurin 不同,我认为您没有理由强迫自己穿上 /NoPadding
的紧身衣; Java /PKCS5Padding
与 OpenSSL 的默认值兼容。对于 CBC 或 CTR,您需要显式设置 IV(将第三个参数设置为 Cipher.init
)以获得确定性结果——并且您必须设置 IV, 或检索 默认的随机数,以产生人们通常想要的 decryptable 结果。 OpenSSL enc -blowfish
默认为 CBC,但明确声明 -bf-cbc
或 -bf-ctr
更清楚。或者 -bf-ecb
如果你 真的 想要欧洲央行,如上所述是不推荐的。
首先,如果你想拥有相同的密文,你必须确保 Scala 和 OpenSSL 加密使用具有相同输入参数的相同确定性加密算法。
由于 OpenSSL 使用 CBC 作为默认模式,我们在 Scala 中也这样做。
import javax.crypto.Cipher
import javax.crypto.spec._
import javax.xml.bind.DatatypeConverter
val cipher = Cipher.getInstance("Blowfish/CBC/NoPadding")
val key = new SecretKeySpec(DatatypeConverter.parseHexBinary("0123456789ABCDEF0123456789ABCDEF"), "Blowfish")
val specIv = new IvParameterSpec(DatatypeConverter.parseHexBinary("0000000000000000"))
cipher.init(Cipher.ENCRYPT_MODE, key, specIv)
val enc = cipher.doFinal("messages".getBytes("UTF-8"))
println(DatatypeConverter.printBase64Binary(enc))
请注意,如果没有填充,输入长度必须是 64 位 Blowfish 块长度的倍数。
使用 OpenSSL,您必须明确指定相同的密钥和初始化向量 (IV)
printf %s "messages" | openssl enc -e -blowfish -nopad -K "0123456789ABCDEF0123456789ABCDEF" -iv "0000000000000000" -base64
对于上面的例子,在这两种情况下你都会得到 JSj0k4FwtG8=
作为密文。
我正在尝试构建一个工具来解密在 Scala 应用程序中加密的 bash 中的内容:
但首先,我必须成功地用两种语言编码相同的消息并使它们相等:
给定密码“0123456789abcdef”
(十六进制:“30313233343536373839616263646566”和字节[]:[48、49、50、51、52、53、54、55、56、57、97, 98、99、100、101、102])
scala> import javax.crypto.Cipher
scala> import javax.crypto.spec.SecretKeySpec
scala> val cipher = Cipher.getInstance("Blowfish")
scala> cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec("0123456789abcdef".getBytes("utf-8"), "Blowfish"))
scala> javax.xml.bind.DatatypeConverter.printBase64Binary(cipher.doFinal("message".getBytes("utf-8")))
res7: String = K679Jz06jmc=
但我无法在 bash 中使用 openssl
重现相同的内容。
$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "0123456789abcdef"
LJ3iFJ2/mYk=
$ echo "message" | openssl enc -a -e -blowfish -nosalt -nopad -k "30313233343536373839616263646566"
JkkJgYv3fQg=
有什么提示吗? 谢谢!
标记 OpenSSL 会更准确,它在任何 shell 或根本没有 shell 时都运行相同。
OpenSSL enc
默认情况下进行 基于密码的 加密,密钥(加上 IV)推导类似于(但不完全)PBKDF1。要使用 密钥 而不是密码进行加密,您需要使用带十六进制的大写 -K
,并且至少需要指定 -iv
的一部分;另一方面 -nosalt
没用。
此外,echo
命令在它回显的数据中添加了一个换行符,'m e s s a g e NL'的加密与[=48=的加密完全不同].某些操作系统和 shells,取决于您使用的 echo
是内置的还是外部的,有办法省略换行符,但它们并不完全相同。 OTOH 所有 POSIX 系统都支持 printf
,因此:
$ printf %s message | openssl enc -blowfish -K 30313233343536373839616263646566 -iv 00 -a
K679Jz06jmc=
编辑:Artjom 是正确的; Java/Scala(可能)默认为 ECB,这是一个坏主意;您应该指定 /CBC
或 /CTR
和填充。与 aventurin 不同,我认为您没有理由强迫自己穿上 /NoPadding
的紧身衣; Java /PKCS5Padding
与 OpenSSL 的默认值兼容。对于 CBC 或 CTR,您需要显式设置 IV(将第三个参数设置为 Cipher.init
)以获得确定性结果——并且您必须设置 IV, 或检索 默认的随机数,以产生人们通常想要的 decryptable 结果。 OpenSSL enc -blowfish
默认为 CBC,但明确声明 -bf-cbc
或 -bf-ctr
更清楚。或者 -bf-ecb
如果你 真的 想要欧洲央行,如上所述是不推荐的。
首先,如果你想拥有相同的密文,你必须确保 Scala 和 OpenSSL 加密使用具有相同输入参数的相同确定性加密算法。
由于 OpenSSL 使用 CBC 作为默认模式,我们在 Scala 中也这样做。
import javax.crypto.Cipher
import javax.crypto.spec._
import javax.xml.bind.DatatypeConverter
val cipher = Cipher.getInstance("Blowfish/CBC/NoPadding")
val key = new SecretKeySpec(DatatypeConverter.parseHexBinary("0123456789ABCDEF0123456789ABCDEF"), "Blowfish")
val specIv = new IvParameterSpec(DatatypeConverter.parseHexBinary("0000000000000000"))
cipher.init(Cipher.ENCRYPT_MODE, key, specIv)
val enc = cipher.doFinal("messages".getBytes("UTF-8"))
println(DatatypeConverter.printBase64Binary(enc))
请注意,如果没有填充,输入长度必须是 64 位 Blowfish 块长度的倍数。
使用 OpenSSL,您必须明确指定相同的密钥和初始化向量 (IV)
printf %s "messages" | openssl enc -e -blowfish -nopad -K "0123456789ABCDEF0123456789ABCDEF" -iv "0000000000000000" -base64
对于上面的例子,在这两种情况下你都会得到 JSj0k4FwtG8=
作为密文。