网络信息安全|第3章:OpenSSL HOWTO
Synopsis: OpenSSL 是一个开源命令行工具,通常用于生成私钥、创建 CSR、生成 SSL/TLS 证书以及识别证书信息等,同时它也可以搭建本地用的私有 CA,从而可以签发数字证书。请先阅读本系列前两篇文章,更多详细用法可以参考本文末尾的附件 openssl-cookbook.pdf
1. OpenSSL 入门
OpenSSL
是一种功能强大的商用级全功能安全工具包,适用于 SSL
协议或 TLS
协议,同时它也是一个通用的加密库。它由 libssl
、libcrypto
和 openssl
三部分组成,具体可参考: https://github.com/openssl/openssl/blob/master/README
查看版本号等信息:
[root@CentOS ~]# openssl version -a OpenSSL 1.0.2k-fips 26 Jan 2017 built on: reproducible build, date unspecified platform: linux-x86_64 options: bn(64,64) md2(int) rc4(16x,int) des(idx,cisc,16,int) idea(int) blowfish(idx) compiler: gcc -I. -I.. -I../include -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -m64 -DL_ENDIAN -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -Wa,--noexecstack -DPURIFY -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DRC4_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASMOPENSSLDIR: "/etc/pki/tls" engines: dynamic
我的系统是 CentOS 7.3,默认安装了 OpenSSL 1.0.2k-fips
,它的配置文件为 /etc/pki/tls/openssl.cnf
如果你想查看 openssl
所支持的所有子命令,可以故意输入无效的选项参数:
[root@CentOS ~]# openssl help openssl:Error: 'help' is an invalid command. Standard commands asn1parse ca ciphers cms crl crl2pkcs7 dgst dh dhparam dsa dsaparam ec ecparam enc engine errstr gendh gendsa genpkey genrsa nseq ocsp passwd pkcs12 pkcs7 pkcs8 pkey pkeyparam pkeyutl prime rand req rsa rsautl s_client s_server s_time sess_id smime speed spkac ts verify version x509 Message Digest commands (see the `dgst' command for more details) md2 md4 md5 rmd160 sha sha1 Cipher commands (see the `enc' command for more details) aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb aes-256-cbc aes-256-ecb base64 bf bf-cbc bf-cfb bf-ecb bf-ofb camellia-128-cbc camellia-128-ecb camellia-192-cbc camellia-192-ecb camellia-256-cbc camellia-256-ecb cast cast-cbc cast5-cbc cast5-cfb cast5-ecb cast5-ofb des des-cbc des-cfb des-ecb des-ede des-ede-cbc des-ede-cfb des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb des-ede3-ofb des-ofb des3 desx idea idea-cbc idea-cfb idea-ecb idea-ofb rc2 rc2-40-cbc rc2-64-cbc rc2-cbc rc2-cfb rc2-ecb rc2-ofb rc4 rc4-40 rc5 rc5-cbc rc5-cfb rc5-ecb rc5-ofb seed seed-cbc seed-cfb seed-ecb seed-ofb zlib
同样的道理,如果你想查看 openssl enc
子命令的帮助文档:
[root@CentOS ~]# openssl enc --help unknown option '--help' options are -in <file> input file -out <file> output file -pass <arg> pass phrase source -e encrypt -d decrypt -a/-base64 base64 encode/decode, depending on encryption flag -k passphrase is the next argument -kfile passphrase is the first line of the file argument -md the next argument is the md to use to create a key from a passphrase. See openssl dgst -h for list. -S salt in hex is the next argument -K/-iv key/iv in hex is the next argument -[pP] print the iv/key (then exit if -P) -bufsize <n> buffer size -nopad disable standard block padding -engine e use engine e, possibly a hardware device. Cipher Types -aes-128-cbc -aes-128-ccm -aes-128-cfb -aes-128-cfb1 -aes-128-cfb8 -aes-128-ctr -aes-128-ecb -aes-128-gcm -aes-128-ofb ...
或者,查看更详细的 man
手册,可以先用 whatis
命令确定 enc
对应的手册名:
1.1 加密与解密
可以使用 对称加密
算法(比如 AES
)来加密数据:
[root@CentOS ~]# openssl enc -aes-128-cfb -salt -in plain.txt -out cipher.txt enter aes-128-cfb encryption password: Verifying - enter aes-128-cfb encryption password: [root@CentOS ~]# file cipher.txt cipher.txt: data
上面使用 AES
分组加密算法,以 128-bit 为一组,采用 CFB 模式(详情见 http://www.madmalls.com/blog/post/encryption-and-decryption/#3-cipher-feedback-cfb) 。执行命令后你需要输入两次相同的密码(解密时需要用到它),加密后的 cipher.txt
默认是二进制格式的文件,如果你用 cat
命令查看它会是乱码。或者你在加密时指定 -a
或 -base64
选项,会将密文转换成 Base64 编码后的纯文本文件:
[root@CentOS ~]# openssl enc -aes-128-cfb -a -salt -in plain.txt -out cipher-base64.txt enter aes-128-cfb encryption password: Verifying - enter aes-128-cfb encryption password: [root@CentOS ~]# file cipher-base64.txt cipher-base64.txt: ASCII text [root@CentOS ~]# cat cipher-base64.txt U2FsdGVkX1/7YJVkp+FABnnnLngDHieHO1vDhU4=
enc
子命令默认省略 -e
选项,表示加密。如果要解密,需要显示指定 -d
选项。另外,需要使用相同的算法和密码,如果加密时还指定过 -a -salt
的话,解密时也需要指定:
# 1. 解密时忘记指定 -a -salt 会失败 [root@CentOS ~]# openssl enc -aes-128-cfb -d -in cipher-base64.txt enter aes-128-cfb decryption password: bad magic number # 2. 成功解密出原始明文 [root@CentOS ~]# openssl enc -aes-128-cfb -d -a -salt -in cipher-base64.txt enter aes-128-cfb decryption password: Hello world.
base64
编码与解码:
1. echo 命令默认会在末尾添加换行符 \n [root@CentOS ~]# echo "encode me" | openssl enc -base64 ZW5jb2RlIG1lCg== 2. 用 -n 选项禁止换行,输出的 base64 编码少了 [root@CentOS ~]# echo -n "encode me" | openssl enc -base64 ZW5jb2RlIG1l 3. 解码(有换行符) [root@CentOS ~]# echo "ZW5jb2RlIG1lCg==" | openssl enc -base64 -d encode me 4. 解码(没有换行符) [root@CentOS ~]# echo "ZW5jb2RlIG1l" | openssl enc -base64 -d encode me[root@CentOS ~]#
1.2 生成随机数
可以使用 rand
子命令生成 伪随机(pseudo-random)
字节
# 1. 生成 10 个字节的随机数,并用 16 进制显示 [root@CentOS ~]# openssl rand -hex 10 d1df889096288e9471f9 # 2. 生成 8 个字节的随机数,并用 base64 编码并显示 (注意不要复制末尾的 = 或 ==) [root@CentOS ~]# openssl rand -base64 8 JvDOMYomQ40=
1.3 密码散列
可以作用 passwd
子命令生成指定密码的散列值,指定 -salt
选项会让生成的散列值更难被猜测出(加点盐,汤的味道就完全改变了...),所以假设你有一个网站,想将用户注册时的密码保存到数据库,为了安全现在都不会直接存明文的密码,而是存密码的散列值,那么为确保生成的散列值更随机,就可以用 rand
子命令先生成伪随机数,再将它赋值给 passwd
子命令的 -salt
选项:
# 1. 使用 $(openssl rand -hex 8) 生成 16 进制的伪随机数,然后用 crypt 算法计算出用户密码的散列值 [root@CentOS ~]# openssl passwd -crypt -salt $(openssl rand -hex 8) Password: 3f6CcU7JTBNt2 # 2. 同样为 -salt 指定伪随机数,但使用基于 MD5 的算法 1 来计算出用户密码的散列值 [root@CentOS ~]# openssl passwd -1 -salt $(openssl rand -hex 8) Password: $1$37904b9d$rqMdive2S0V2Gy0EaVpcb0 # 3. 这次使用 apr1 算法来计算散列值 [root@CentOS ~]# openssl passwd -apr1 -salt $(openssl rand -hex 8) Password: $apr1$82e126f5$hKlvdL6uie.PEA62z.7Ap0
1.4 提取摘要
可以使用 dgst
子命令结合指定的散列函数算法来生成数据的 摘要(digest)
# MD5 digest [root@CentOS ~]# openssl dgst -md5 plain.txt MD5(plain.txt)= fa093de5fc603823f08524f9801f0546 或者: [root@CentOS ~]# openssl md5 plain.txt MD5(plain.txt)= fa093de5fc603823f08524f9801f0546 # SHA1 digest [root@CentOS ~]# openssl dgst -sha1 plain.txt SHA1(plain.txt)= 4177876fcf6806ef65c4c1a1abf464087bfbf337 或者: [root@CentOS ~]# openssl sha1 plain.txt SHA1(plain.txt)= 4177876fcf6806ef65c4c1a1abf464087bfbf337 # SHA256 digest [root@CentOS ~]# openssl dgst -sha256 plain.txt SHA256(plain.txt)= 6472bf692aaf270d5f9dc40c5ecab8f826ecc92425c8bac4d1ea69bcbbddaea4 或者: [root@CentOS ~]# openssl sha256 plain.txt SHA256(plain.txt)= 6472bf692aaf270d5f9dc40c5ecab8f826ecc92425c8bac4d1ea69bcbbddaea4
尽管输出格式不同,但 openssl dgst -md5
与广泛使用的 md5sum
命令创建的摘要相同:
[root@CentOS ~]# openssl dgst -md5 plain.txt MD5(plain.txt)= fa093de5fc603823f08524f9801f0546 [root@CentOS ~]# md5sum plain.txt fa093de5fc603823f08524f9801f0546 plain.txt
同样地 sha1sum
和 sha256sum
命令也会分别提取相同的摘要,由于 MD5
和 SHA1
不再安全,建议使用 SHA2 或 SHA3 系列的单向加密算法,比如 SHA256
或 SHA384
网络信息安全|第1章:密码学基础 - 加密与解密 讲过,结合散列函数和一个密钥,生成的 HMAC 值可以更安全地进行消息认证:
1. 发送方用 SHA256 和密钥 123 生成 /tmp/passwd 文件的 HMAC 值 [root@CentOS ~]# cp /etc/passwd /tmp [root@CentOS ~]# openssl dgst -sha256 -hmac 123 /tmp/passwd HMAC-SHA256(/tmp/passwd)= 2cecd38c19fa70d075ed9fecadace6eafbaf8ed3c4405c6195ae315f19c1f6ee 2. 攻击者不知道密钥是 123,所以他生成的 HMAC 就会不一样 [root@CentOS ~]# openssl dgst -sha256 -hmac 456 /tmp/passwd HMAC-SHA256(/tmp/passwd)= 53aa4d4999530b95146b18fb5cf3096d463b98703de0510e95835981b4a594e2 3. 假设攻击者修改了 /tmp/passwd,并发送给接收者。接收者用发送方同样的密钥 123 就会生成不一样的 HMAC,从而证明消息被篡改了 [root@CentOS ~]# echo "Add new line" >> /tmp/passwd [root@CentOS ~]# openssl dgst -sha256 -hmac 123 /tmp/passwd HMAC-SHA256(/tmp/passwd)= 604424332302eed997c81fb9acf4dde28b496471cea247dfd018c039d9c6c38f
1.5 数字签名
对 Golang 源代码 go1.12.5.src.tar.gz
提取摘要后,再用 私钥
加密摘要形成 数字签名
(如何生成私钥和公钥请参考本文章节 2.1):
1. 产生 RSA 私钥 [root@CentOS ~]# openssl genrsa -out mykey.pem 2048 2. 用 SHA256 算法提取提要,并用私钥加密摘要生成数字签名 go1.12.5.src.tar.gz.sha256 [root@CentOS ~]# openssl dgst -sha256 \ -sign mykey.pem \ -out go1.12.5.src.tar.gz.sha256 \ go1.12.5.src.tar.gz
用 公钥
解密 数字签名
,并自动计算原始文件的摘要,再对比是否一致:
1. 提取公钥 [root@CentOS ~]# openssl rsa -in mykey.pem -pubout -out mypub.pem 2. 验证通过 [root@CentOS ~]# openssl dgst -sha256 \ -verify mypub.pem \ -signature go1.12.5.src.tar.gz.sha256 \ go1.12.5.src.tar.gz Verified OK 3. 当你篡改了原始文件后,验证失败 [root@CentOS ~]# echo 1234 >> go1.12.5.src.tar.gz [root@CentOS ~]# openssl dgst -sha256 \ -verify mypub.pem \ -signature go1.12.5.src.tar.gz.sha256 \ go1.12.5.src.tar.gz Verification Failure
1.6 密码套件
[root@CentOS ~]# openssl ciphers -v ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ...
Kx
表示密钥交换算法,Au
表示身份验证算法,Enc
表示对称加密算法,Mac
表示数据完整性检查算法
比如 Nginx 会配置 ssl_ciphers
,假设此参数的值为 ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE
,那么这个密码列表字符串包含哪些密码套件呢?它们的优先级是怎样呢?
[root@CentOS ~]# openssl ciphers -v 'ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE' ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384 ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384 ...
更多说明请参考文末附件 openssl-cookbook.pdf
第 33 页开始的 Cipher Suite Selection
1.7 Diffie-Hellman parameters
生成 DH 参数会根据你的计算机硬件的性能,可能需要几分钟或几个小时,所以添加 nohup ... &
让它在后台运行
[root@CentOS ~]# nohup openssl dhparam -out dhparams.pem 4096 & [root@CentOS ~]# jobs [1]+ Running nohup openssl dhparam -out dhparams.pem 4096 &
注意: IETF 在 RFC 7919 中建议不要使用自己生成的随机 DH parameters,而应该使用 IETF 预定义的 DHE groups,比如 ffdhe2048
、ffdhe3072
或 ffdhe4096
(定义在 RFC 7919 的末尾附录中),因为这些组经过审核,可能比随机生成的组更能抵御攻击
1.8 Curve25519 key pair
1. 生成私钥 [root@CentOS ~]# openssl genpkey -algorithm x25519 -out x25519-priv.pem [root@CentOS ~]# cat x25519-priv.pem -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEIJDcv6okLPjy2xEByA0gR/Rp4AuDJmpTztYRsq9/vnlb -----END PRIVATE KEY----- 2. 导出公钥 [root@CentOS ~]# openssl pkey -in x25519-priv.pem -pubout -out x25519-pub.pem [root@CentOS ~]# cat x25519-pub.pem -----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEAgUoh+pduB5s5LGy5YeCJoF06qKXWuV05pLaiVk+BHH4= -----END PUBLIC KEY----- 3. 查看 [root@CentOS ~]# openssl pkey -noout -text < x25519-priv.pem X25519 Private-Key: priv: 90:dc:bf:aa:24:2c:f8:f2:db:11:01:c8:0d:20:47: f4:69:e0:0b:83:26:6a:53:ce:d6:11:b2:af:7f:be: 79:5b pub: 81:4a:21:fa:97:6e:07:9b:39:2c:6c:b9:61:e0:89: a0:5d:3a:a8:a5:d6:b9:5d:39:a4:b6:a2:56:4f:81: 1c:7e
2. 数字证书
OpenSSL 最常用的功能是用于生成 私钥
,创建 CSR
,生成 SSL/TLS 数字证书
以及识别证书信息等
证书是按什么标准生成?证书的基本结构是什么?谁来签发和管理证书?为了解决这一系列的问题,于是出现了 PKI
0 条评论
评论者的用户名
评论时间暂时还没有评论.