网络信息安全|第3章:OpenSSL HOWTO

  • 原创
  • Madman
  • /
  • /
  • 0
  • 1265 次阅读

网络信息安全-min.jpg

Synopsis: OpenSSL 是一个开源命令行工具,通常用于生成私钥、创建 CSR、生成 SSL/TLS 证书以及识别证书信息等,同时它也可以搭建本地用的私有 CA,从而可以签发数字证书。请先阅读本系列前两篇文章,更多详细用法可以参考本文末尾的附件 openssl-cookbook.pdf

1. OpenSSL 入门

OpenSSL 是一种功能强大的商用级全功能安全工具包,适用于 SSL 协议或 TLS 协议,同时它也是一个通用的加密库。它由 libssllibcryptoopenssl 三部分组成,具体可参考: 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 对应的手册名:

[root@CentOS ~]# whatis enc
enc (1ssl)           - symmetric cipher routines
[root@CentOS ~]# man 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

同样地 sha1sumsha256sum 命令也会分别提取相同的摘要,由于 MD5SHA1 不再安全,建议使用 SHA2 或 SHA3 系列的单向加密算法,比如 SHA256SHA384

网络信息安全|第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,比如 ffdhe2048ffdhe3072ffdhe4096(定义在 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 数字证书 以及识别证书信息等

未经允许不得转载: LIFE & SHARE - 王颜公子 » 网络信息安全|第3章:OpenSSL HOWTO

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.

专题系列