Blowfish在Java/Scala中加密,在bash中解密

Blowfish在Java/Scala中加密,在bash中解密,java,bash,scala,encryption,blowfish,Java,Bash,Scala,Encryption,Blowfish,我正在尝试构建一个工具来解密在scala应用程序中加密的bash中的内容: 但首先,我必须成功地用两种语言编码相同的信息,并使它们相等: 给定密码短语“0123456789abcdef”(十六进制:“303132333435363373839616263646566”和字节[]:[48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102]) 但是我不能在bash中用openssl复制同样的内容 $ echo "message" | openssl en

我正在尝试构建一个工具来解密在scala应用程序中加密的bash中的内容:

但首先,我必须成功地用两种语言编码相同的信息,并使它们相等:

给定密码短语“0123456789abcdef”
(十六进制:“303132333435363373839616263646566”和字节[]:[48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102])

但是我不能在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
命令向其回显的数据添加一条换行符,并且“ME s a g e NL”的加密与“ME s a g e”的加密完全不同。一些操作系统和shell,取决于您使用的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,或检索默认的随机值,以生成人们通常想要的可解密结果。OpenSSL
enc-blowfish
默认为CBC,但更清楚的是显式地声明
-bf CBC
-bf ctr
。或者
-bf ecb
,如果您真的想要ecb,如上所述是不推荐的。

标记OpenSSL会更准确,它可以从任何shell或根本没有shell运行相同的内容

OpenSSL
enc
默认情况下进行基于密码的加密,密钥(加上IV)派生类似于(但不完全是)PBKDF1。要使用密钥而不是密码进行加密,需要将大写字母
-K
与十六进制一起使用,并且需要至少指定
-iv
的一部分;另一方面,
-nosalt
是无用的

另外,
echo
命令向其回显的数据添加一条换行符,并且“ME s a g e NL”的加密与“ME s a g e”的加密完全不同。一些操作系统和shell,取决于您使用的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,或检索默认的随机值,以生成人们通常想要的可解密结果。OpenSSL
enc-blowfish
默认为CBC,但更清楚的是显式地声明
-bf CBC
-bf ctr
。或者
-bf ecb
,如果您确实想要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)


在上述示例中,您将在这两种情况下获得作为密文的
JSj0k4FwtG8=

首先,如果您想要拥有相同的密文,您必须确保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)


在上面的例子中,在这两种情况下,您都会得到作为密文的
JSj0k4FwtG8=

密码短语或密码不是密钥。您应该使用PBKDF(基于密码的密钥派生函数)从密码中创建密钥。否则,如果必须,请以十六进制或64进制指定二进制密钥。请注意,Java8JRE在
Java.util
中有一个
Base64
类。一般建议:始终使用完全限定的密码字符串
Cipher.getInstance(“河豚”)可能会产生不同的密码。它很可能导致“河豚/ECB/PKCS5P添加”
,但不一定非得如此。如果它发生更改,您将失去不同JVM之间的兼容性。请不要使用。它是确定性的,因此在语义上不安全。您至少应该使用随机模式,如或。最好是对密文进行身份验证,这样就不可能进行类似的攻击。这可以通过诸如GCM或EAX之类的经过身份验证的模式或SCH来完成