背景
在工作中用到了Java 的Blowfish加解密,后改为openssl命令实现,发现openssl有很多不熟悉的地方,进行了简单的探索,再此把这次探索的内容记录下来。主要是进行enc命令的探索。
命令说明
命令结构
openssl command [ command_opts ] [ command_args ]
enc 命令
openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e]
[-d] [-a/-base64] [-A] [-k password] [-kfile filename] [-K key] [-iv IV] [-S salt]
[-salt] [-nosalt] [-z] [-md] [-p] [-P] [-bufsize number] [-nopad] [-debug] [-none]
[-engine id]
选项说明:
-ciphername:对称算法名称,此命令有两种使用方式:-ciphername方式或者省略enc直接使用ciphername。
-in filename:要加密/解密的输入文件,默认为标准输入。
-out filename:要加密/解密的输出文件,默认为标准输出。
-pass arg:输入文件如果有密码保护,指定密码来源。
-e:进行加密操作,默认操作。可以省略
-d:进行解密操作。
-a:使用base64编码对加密结果进行处理。加密后进行base64编码,解密前进行base64解密。
-base64:同-a选项。
-A:默认情况下,base64编码为一个多行的文件。使用此选项,可以让生成的结果为一行。解密时,必须使用同样的选项,否则读取数据时会出错。
-k:指定加密口令,不设置此项时,程序会提示用户输入口令。
-kfile:指定口令存放文件。可以从这个口令存放文件的第一行读取加密口令。
-K key:使用一个16进制的输入口令。如果仅指定-K key而没有指定-k password,必须用-iv选项指定IV。当-K key和-k password都指定时,用-K选项给定的key将会被使用,而使用password来产生初始化向量IV。不建议两者都指定。
-iv IV:手工指定初始化向量(IV)的值。IV值是16进制格式的。如果仅使用-K指定了key而没有使用-k指定password,那么就需要使用-iv手工指定IV值。如果使用-k指定了password,那么IV值会由这个password的值来产生。
-salt:产生一个随机数,并与-k指定的password串联,然后计算其Hash值来防御字典攻击和rainbow table攻击。
-S salt:使用16进制的salt。
-nosalt:表示不使用salt。
-z:压缩数据(前提是OpenSSL编译时加入了zip库)。
-md:指定摘要算法。如:MD5 SHA1 SHA256等。
-p:打印出使用的salt、口令以及初始化向量IV。
-P:打印出使用的salt、口令以及IV,不做加密和解密操作,直接退出。
-bufsize number:设置I/O操作的缓冲区大小。因为一个加密的文件可能会很大,每次能够处理的数据是有限的。
-nopad:没有数据填充(主要用于非对称加密操作)。
-debug:打印调试信息。
-none:不对数据进行加密操作。
-engine:指定硬件引擎。
salt(盐)、-k(密码)、key (-K)、iv之间的关系探索
加解密的时候我们真正使用的-K iv来进行字符的加解密,但是我们有时并不输入长长的key和iv,而是使用密码(-k),为了是防止字典攻击,彩虹表攻击我们使用salt。使用salt的时候默认都是随机生成的(-p可以打印出来),每次的key和iv都不一样,但是解密的时候却只需要知道密码就可以这是为什么?
不加salt情况
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -a -bf-cbc -p -nosalt
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
Nmd5naBmros=
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -a -bf-cbc -p -nosalt
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
Nmd5naBmros=
#解密
root@ucss2:~# echo "Nmd5naBmros=" | openssl enc -k "passwd" -a -bf-cbc -p -nosalt -d
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
asd
每次的key和iv 都一样,所以生成base64密文都一样
加salt情况
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -a -bf-cbc -p
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=7E30AD9247349924
key=E911329C8723C900503D78FEA94B9AC3
iv =DB89BEB4988CB164
U2FsdGVkX19+MK2SRzSZJKZFQRxafkGT
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -a -bf-cbc -p
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=A568CC47507BFB58
key=14271A17828F2C5C4B542AF96DF80FBC
iv =4DB21FE1637E26E0
U2FsdGVkX1+laMxHUHv7WE7VSKbyzIVD
root@ucss2:~# echo "U2FsdGVkX1+laMxHUHv7WE7VSKbyzIVD" | openssl enc -k "passwd" -a -bf-cbc -p -d
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=A568CC47507BFB58
key=14271A17828F2C5C4B542AF96DF80FBC
iv =4DB21FE1637E26E0
asdroot@ucss2:~#
root@ucss2:~# echo "U2FsdGVkX19+MK2SRzSZJKZFQRxafkGT" | openssl enc -k "passwd" -a -bf-cbc -p -d
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=7E30AD9247349924
key=E911329C8723C900503D78FEA94B9AC3
iv =DB89BEB4988CB164
asdroot@ucss2:~#
因为salt是随机的,每次的key和iv都不一样,导致生成的密文每次都不相同,这个时候就有疑问了,生成密文的时候是通过pass和salt,为什么解密的时候确不用???(怀疑密文中有salt)
加密:passwd+salt(通过某些算法生成)>key iv
解密:同样需要key iv ,但是我们在解密的时候却只知道 passwd,要知道我们是对称加密,所以还需要找到和加密相同的key iv
通过二进制查看对比加salt和不加salt密文
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -bf-cbc -p -out salt.bin
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
salt=965804FC4937FE54
key=559DA0581998B7E17AE08F3BBE296528
iv =E0037425FB5962EA
root@ucss2:~# xxd salt.bin
00000000: 5361 6c74 6564 5f5f 9658 04fc 4937 fe54 Salted__.X..I7.T
00000010: f55d bd06 2720 3eb8 .]..' >.
root@ucss2:~# echo -n "asd" | openssl enc -k "passwd" -bf-cbc -p -nosalt -out nosalt.bin
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
root@ucss2:~# xxd nosalt.bin
00000000: 3667 799d a066 ae8b 6gy..f..
看出加salt的二进制文件比不加盐的多一行,另外哪一样里面存的就是salt信息(965804FC4937FE54)
这样咱们就可以很清楚就是因为在密文的开头放了salt所以我们能够只用密码就能够解密。
解密时,也需要指定是否有salt,不能有salt使用nosalt,也不能nosalt使用salt
root@ucss2:~# openssl enc -k "passwd" -bf-cbc -p -in salt.bin -d -nosalt
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
bad decrypt
139660630045120:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:564:
ЗM
ē Э`.
root@ucss2:~# openssl enc -k "passwd" -bf-cbc -p -in nosalt.bin -d
error reading input file
问题验证
密文的解密,既可以通过passwd也可以通过key iv,去解密。
但是在实际解密的时候
root@ucss2:~# openssl enc -bf-cbc -p -in nosalt.bin -d -K 0D6BE69B264717F2DD33652E212B1731 -iv 04B4A647B7C11AE7
salt=C0E4E7ACFE7F0000
key=0D6BE69B264717F2DD33652E212B1731
iv =04B4A647B7C11AE7
asdroot@ucss2:~#
root@ucss2:~#
root@ucss2:~#
root@ucss2:~# openssl enc -bf-cbc -p -in salt.bin -d -K 559DA0581998B7E17AE08F3BBE296528 -iv E0037425FB5962EA
salt=802A80CAFC7F0000
key=559DA0581998B7E17AE08F3BBE296528
iv =E0037425FB5962EA
bad decrypt
140338444927424:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:564:
ªZBDL89¤?IMroot@ucss2:~#
root@ucss2:~# openssl enc -bf-cbc -p -in salt.bin -d -K 559DA0581998B7E17AE08F3BBE296528 -iv E0037425FB5962EA -nosalt
key=559DA0581998B7E17AE08F3BBE296528
iv =E0037425FB5962EA
bad decrypt
140719439557056:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:564:
ªZBDL89¤?IMroot@ucss2:~#
没有salt的可以通过key iv解密,但是有salt的却不能。
因为上面说过(passwd+salt(通过某些算法生成)>key iv) ,密文中带有salt。此时用key iv去解析完全不用salt 不用密码,只要把密文中的salt给删除就应该能用key iv解析。
进行salt.bin文件的改造
vim -b salt.bin
执行
:%!xxd
删除第一行,然后更改第二行的序号。
更改后
:%!xxd -r
wq
保存退出。
root@ucss2:~# openssl enc -bf-cbc -p -in salt.bin -d -K 559DA0581998B7E17AE08F3BBE296528 -iv E0037425FB5962EA
salt=A02A1A12FC7F0000
key=559DA0581998B7E17AE08F3BBE296528
iv =E0037425FB5962EA
asdroot@ucss2:~#
修改后加salt的密文也能够被解析出来。
结论
- 在我们使用的时候最好加salt,同样的内容生成的密文却不同,这样可以保证我们的密文的安全性。
- salt会在密文中保存,在解密的时候,通过密码和密文中的salt可以生成和加密时一样的key iv从而保证我们的密文能够正常的解密。
- 有salt的密文我们可以修改然后通过key iv 就能正常进行解析(key iv 和密码同样重要)。
- 知道 key iv 是否能反推密码,不能,因为生成key iv用到了md5(摘要算法)不能反推。
- 使用 key iv 的能否加salt,不能,因为salt是为了生成key iv,已经有个key iv 之后salt就是无效的
相关文献
OpenSSL AES 算法中 Key 和 IV 是如何生成的?
Linux VIM编辑二进制文件
加盐的目的
注意事项
在进行字符串加密时用-n,否则加密字符串加密后带换行
echo -n “asd” | openssl enc -K 38653466333761623535636533373933 -iv 6662636463663630 -a -bf-cbc