我正在尝试构建一个工具来解密在scala应用程序中加密的bash中的内容:
但首先,我必须成功地用两种语言编码相同的消息,并使它们相等:
给定密码短语"0123456789abdedf">
(十六进制:"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=
有什么提示吗?谢谢
首先,如果你想拥有相同的密文,你必须确保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=
作为密文。
标记OpenSSL会更准确,它可以从任何shell或根本不从shell运行。
OpenSSLenc
默认情况下执行基于密码的加密,其密钥(加IV)派生类似于(但不完全)PBKDF1。要使用密钥而不是密码进行加密,您需要使用带十六进制的大写-K
,并且您需要指定-iv
的至少一部分;而CCD_ 6则是无用的。
此外,echo
命令会在其回显的数据中添加一条换行符,并且"m e s a g e NL"的加密与"m e s a g e"的加密完全不同。根据您使用的echo
是内置的还是外部的,一些操作系统和shell可以省略换行符,但它们并不完全相同。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,或检索默认的随机结果,以产生人们通常想要的可解密的结果。OpenSSLenc -blowfish
默认为CBC,但更清楚的是显式声明-bf-cbc
或-bf-ctr
。或者-bf-ecb
,如果您真的想要ECB,如上所述,这是不推荐的。