简介
- 1995年,Eric Andrew Young 和 Tim J. Hudson 开发了 SSLeay。这是一个开源的SSL实现,它支持X.509v3证书、PKCS#10证书请求、SSL2和SSL3。(注:eay是Eric Andrew Young的首字母)
- 1998年,OpenSSL项目启动,它基于SSLeay的代码进行开发。
OpenSSL可以分成三个主要部分:
- 密码算法库:实现了目前大部分主流的密码算法和标准。主要包括对称算法、非对称算法、散列算法、数字签名和认证、X509数字证书标准、PKCS12、PKCS7等标准。
- SSL协议库:完全实现SSL协议和TLS协议。
- 命令行工具:基于密码算法库和SSL协议库实现的命令。包括各种算法的加密程序和各种类型密钥的产生程序、证书签发和验证程序、SSL连接测试程序等。
版本
在Qt中碰到的几个版本(注:3.0开始版本规则又发生改变,版本号不再用字母后缀):
版本 | 初始发布日期 | 备注 |
---|---|---|
1.0.2 | 2015年1月22日 | 1.0.2u(2019年12月20日) |
1.1.1 | 2018年9月11日 | 1.1.1w(2023年9月11日) |
3.0 | 2021年9月7日 | (2026年9月7日) |
注:OpenSSL1.1和OpenSSL1.0二进制和源码都不兼容
动态库名称
OpenSSL库包含两个动态库(共享库)文件:
- libssl
- libcrypto
前者实现ssl的基本功能,后者是各种加密算法。
OpenSSL1.1之前的版本,在Windows下用MSVC编译的产物,名字比较怪异,是:
- ssleay32 (等价于 libssl32)
- libeay32
初次见到它是在Windows下,有些懵
好消息是,从OpenSSL1.1开始,在Windows下的命名也规范统一了
libssl-1_1(-x64).dll
libcrypto-1_1(-x64).dll
命令行工具
OpenSSL支持的命令列表,可以通过openssl help
查看
openssl help
它会返回内容很长,包括:
标准命令列表
Standard commands
asn1parse ca ciphers cms
crl crl2pkcs7 dgst dhparam
dsa dsaparam ec ecparam
...
摘要命令
Message Digest commands (see the `dgst' command for more details)
blake2b512 blake2s256 gost md4
md5 rmd160 sha1 sha224
...
以及
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 aria-128-cbc aria-128-cfb
...
算法
对称加密算法(Cipher)
特点是文件加密和解密使用相同的密钥,即加密密钥也用作解密密钥。特点:加解密速度很快,但密钥丢失,会造成安全隐患。
- https://www.openssl.org/docs/man1.1.1/man1/enc.html
通过openssl enc -list
命令可以获取算法列表
- AES
- Blowfish
- Camelia
- Poly1305
- SEED
- CAST-128
- DES
- IDEA
- RC2
- RC4
- RC5
- Triple DES
- GOST 28147-89
- SM4
加解密使用
使用AES加密:
openssl enc -aes-256-cbc -salt -in input.txt -out encrypted.enc
解密
openssl enc -aes-256-cbc -d -in encrypted.enc -out decrypted.txt
加解密过程中会提示输入密码,类似下面这样:
enter AES-256-CBC decryption password:
非对称加密算法(Public-key cryptography)
非对称加密算法需要两个密钥:公开密钥(public-key)和私有密钥 (private-key)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密(公私钥互为加解密关系)。
相对于对称加密算法来说,非对称加密算法速度很慢。
- RSA
- DSA
- Diffie-Heliman key exchange(迪菲-赫尔曼密钥交换)
- Elliptic curve(椭圆曲线)
- X25519
- Ed25519
- X448
- Ed448
- GOST R34.10-2001
- SM2
对非对称加密算法,一些知识点:
- 使用公钥操作数据(公钥加密,私钥解密) -> 加密
- 使用私钥对原文的摘要操作(私钥加密,公钥解密) -> 签名
- 公钥和私钥可以互相加密解密(对应上两条)
- 公钥对外公开,但私钥一定不能泄露。
密钥操作
OpenSSL3 默认生成密钥格式(PKCS#8)和之前(PKCS#1)不同。
直观差异体现在密钥文件的开头:
PKCS#1(只用于RSA)
-----BEGIN RSA PRIVATE KEY-----
和PKCS#8(也适用于其他算法的私钥,使用OID进行区分)
-----BEGIN PRIVATE KEY-----
在OpenSSL3中,可以使用-traditional
选项来生成老的格式。
两个格式具体差异,详见:DER格式小结
OpenSSL 1.1下
生成密钥(PKCS#1格式)
$ openssl genrsa -out rsa.key 1024
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDBqdNEz15gMCAH6FQTsqxFFExolLg2VUAdBxks7pl7aIIi4qE
....
/Wo83kTObo8lOMq7MPwFlCWoXNxYZpVdb3WU6eNNLYY=
-----END RSA PRIVATE KEY-----
查看私钥内容
$ openssl rsa -in rsa.key -text
RSA Private-Key: (1024 bit, 2 primes)
modulus:
00:c1:a9:d3:44:cf:5e:60:30:20:07:e8:54:13:b2:
ac:45:14:4c:68:94:b8:36:55:40:1d:07:19:2c:ee:
99:7b:68:82:22:e2:a1:33:b0:db:92:94:be:f0:13:
2b:03:ee:37:09:82:f1:3b:3d:cd:2b:2f:df:5e:8a:
....
- https://www.openssl.org/docs/man1.1.1/man1/openssl-pkcs8.html
PKCS#1到PKCS#8转换(-nocrypt生成不带密码的私钥)
$ openssl.exe pkcs8 -in 1.pem -topk8 -out 2.pem -nocrypt
PKCS#8 到PKCS#1转换
$ openssl.exe rsa -in 2.pem -out 3.pem
OpenSSL 3.0下
生成密钥(PKCS8格式):
$ openssl genrsa -out rsa.key 1024
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMXQYsn+DeflrheT
...
Lm9g7JNkTzCgiwQ=
-----END PRIVATE KEY-----
查看密钥:
$ openssl rsa -in rsa.key -text
Private-Key: (1024 bit, 2 primes)
modulus:
00:c4:3d:a2:07:14:01:d2:68:20:f5:8b:72:89:4f:
42:58:a9:70:0f:94:1e:76:47:d0:ea:be:93:c5:ae:
...
导出公钥:
$ openssl rsa -in rsa.key -pubout -out rsa.pub
$ openssl rsa -in rsa.key -pubout
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBqdNEz15gMCAH6FQTsqxFFEx
...
aW+wLBQ5O4mCIQyALQIDAQAB
-----END PUBLIC KEY-----
writing RSA key
注:-in -out 默认都是私钥,通过-pubout指定输出公钥;同样通过-pubin指定输入公钥。
PEM 与 DER转换
输出格式默认都是pem格式,如果要使用der格式,可以使用 -outform DER
指定:
$ openssl rsa -in rsa.pem -outform DER -out rsa.der
加解密操作
使用公钥加密文件(openssl命令行只能使用公钥加密,其C API支持私钥加解密):
$ openssl pkeyutl -encrypt -in a.txt -pubin -inkey rsa.pub -out rsa_chiper.enc
即使是如下这样写,还是用的私钥文件中的公钥进行的加密:
openssl pkeyutl -encrypt -in a.txt -inkey rsa.key -out rsa_chiper.enc
使用私钥解密文件:
$ openssl pkeyutl -decrypt -in rsa_chiper.enc -inkey rsa.key -out a.txt.2
注意:
- 填充方式可通过选项指定:
-pkeyopt rsa_padding_mode:oaep
签名与验证
签名(输入必须是哈希值,该命令不会对输入内容执行哈希操作)
openssl pkeyutl -sign -in sha384.txt -inkey rsa.key -out sha384.sig
验证
openssl pkeyutl -verify -in sha384.txt -pubin -inkey rsa.pub -sigfile sha384.sig
OpenSSH
注意,OpenSSH生成公钥私钥格式与OpenSSL不同!!不要混淆
它的私钥头部如下:
-----BEGIN OPENSSH PRIVATE KEY-----
它生成私钥的命令
ssh-keygen -t rsa -b 4096
散列函数(Cryptographic hash Functions)
散列函数 又称 哈希函数、摘要算法。它是一种单向算法,用户可以通过散列函数对目标信息生成一段特定长度的唯一的Hash值,却不能通过这个Hash值逆向获得目标信息。
特点:不可逆,加密后值很小(128位,256位,512位等)。
散列函数有两大家族:
-
MD:Message Digest Algorithm
-
MD4:1990年发布。早已被攻破。
-
MD5:Message Digest 5,1992年发布。早已被攻破,不适用于安全认证或数字签名。
-
SHA:安全散列算法(Secure Hash Algorithm),由美国国家安全局(NSA)设计,美国国家标准与技术研究所发布。
-
SHA-0:1993年发布后,但很快被撤回。
- SHA-1:1995年发布,使用很广泛(用于 TLS, GnuPG, SSH, IPsec等)。2017年已经被荷兰CWI和Google攻破。
- SHA-2:2001年发布,包括SHA-224, SHA-256, SHA-384, SHA-512, SHA512/224, SHA512/256。
- SHA-3:2015年发布。
算法列表
- https://www.openssl.org/docs/manmaster/man1/openssl-dgst.html
OpenSSL支持的算法列表,可以通过openssl dgst -list
命令获得:
$ openssl dgst -list
Supported digests:
-blake2b512 -blake2s256 -md4
-md5 -md5-sha1 -mdc2
-ripemd -ripemd160 -rmd160
-sha1 -sha224 -sha256
-sha3-224 -sha3-256 -sha3-384
-sha3-512 -sha384 -sha512
-sha512-224 -sha512-256 -shake128
-shake256 -sm3 -ssl3-md5
-ssl3-sha1 -whirlpool
也可以通过openssl list -digest-algorithms
命令(这个返回的列表比较长,多出来的别名?):
$ openssl list -digest-algorithmsRSA-MD4 => MD4
RSA-MD5 => MD5
RSA-MDC2 => MDC2
RSA-RIPEMD160 => RIPEMD160
RSA-SHA1 => SHA1
RSA-SHA1-2 => RSA-SHA1
RSA-SHA224 => SHA224
RSA-SHA256 => SHA256
RSA-SHA3-224 => SHA3-224
RSA-SHA3-256 => SHA3-256
RSA-SHA3-384 => SHA3-384
RSA-SHA3-512 => SHA3-512
RSA-SHA384 => SHA384
RSA-SHA512 => SHA512
RSA-SHA512/224 => SHA512-224
RSA-SHA512/256 => SHA512-256
RSA-SM3 => SM3
BLAKE2b512
BLAKE2s256
id-rsassa-pkcs1-v1_5-with-sha3-224 => SHA3-224
id-rsassa-pkcs1-v1_5-with-sha3-256 => SHA3-256
id-rsassa-pkcs1-v1_5-with-sha3-384 => SHA3-384
id-rsassa-pkcs1-v1_5-with-sha3-512 => SHA3-512
MD4
md4WithRSAEncryption => MD4
MD5
MD5-SHA1
md5WithRSAEncryption => MD5
...
生成摘要
要获得一个文件的md5值,可以使用dgst命令:
$openssl dgst -md5 dbzhang800.txt
MD5(dbzhang800.txt)= 520e37bcab36e7f6c63a9fe8571fef5c
或者直接用md5命令
$openssl md5 dbzhang800.txt
将结果以二进制输出到文件
$openssl dgst -md5 -binary -out dgst.out dbzhang800.txt
使用16进制编辑器查看dgst.out结果
00000000: 520e 373f 3f36 3f3f 3f3a 3f3f 571f 3f5c
00000010: 0a
默认的dgst是SHA256:
$ openssl dgst dbzhang800.txt
SHA256(dbzhang800.txt)= a327231c982850cb61eecfb3da89aa6831d09d2c9e209acb58658faa78ccfeeb
加密后的值被称为hash值,hash值用于确保数据的完整性,但是不能保证数据传输存在身份认证机制。
数字签名
数字签名它是基于非对称密钥加密技术与数字摘要算法技术的应用,只有私钥拥有者才能产生别人无法伪造的一段数字串。
发送方通过私钥加密后数字签名发送给接收方,接收方使用公钥解密,通过对比解密后的摘要和使用Hash函数对数据电文进行计算的摘要 判定其是否被篡改。
生成签名
$ openssl dgst -sha256 -sign rsa.key -out signature.sign a.txt
验证签名
$ openssl dgst -sha256 -verify rsa.pub -signature signature.sign a.txt
Verified OK
结果为 Verification failure 或 Verified OK
OpenSSL 作为CA
配置文件
在Ubuntu下,配置文件在 /etc/ssl/openssh.cnf
在Windows下安装OpenSSL-Win32,安装目录下有一个配置文件openssh.cnf
如果报错,可通过环境变量来指定它。
set OPENSSL_CONF=[path-to-OpenSSL-install-dir]\openssl.cnf
[ ca ]
default_ca = CA_default # The default ca section
####################################################################
[ CA_default ]
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several certs with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
...
建立CA目录
.
`-- myCA/
|-- index.txt
|-- newcerts/
|-- private/
`-- serial
- private/ 存放证书私钥
- serial 里面写入序列号,比如可以写入“8101”或其他数字,后期递增 echo 8101 > serial
CA自签名证书
生成私钥,并放入我们在配置文件中指定的位置
openssl genrsa -des3 -out myCA\private\cakey.pem 2048
生成CA证书请求
openssl.exe req -new -days 7300 -key myCA\private\cakey.pem -out myCA\careq.pem
签名证书,将其放置到配置文件期望的位置
openssl.exe ca -selfsign -in myCA\careq.pem -out myCA\cacert.pem
在该步骤中,配置文件开始起作用了,当前目录结构:
.
`-- myCA
|-- cacert.pem
|-- careq.pem
|-- index.txt
|-- index.txt.attr
|-- index.txt.old
|-- newcerts
| `-- 8101.pem
|-- private
| `-- cakey.pem
|-- serial
`-- serial.old
接下来,该CA就可以为其他csr生成证书了。
OpenSSL命令行参数备忘
-
非对称算法:-in -out 默认都是私钥,通过-pubout指定输出公钥;同样通过-pubin指定输入公钥。
-
通过s client可以读取网站的证书
$ openssl s_client -connect blog.debao.me:443
-
x509和pkcs12这两个命令可用于操作证书,比如证书格式之间的转换:
openssl pkcs12 -export -out certificate.pfx -inkey privatekey.key -in cert.crt
-
生成 证书请求文件 (回答它的提问,完成过程),而后用csr去找CA机构申请正式的证书。
openssl req -new -key x.key -out x.csr
Qt 与 OpenSSL
Qt官方提供的Windows下的安装包,默认不打包OpenSSL。在Qt5.13之前,如果需要QSslScocket功能,需要手动安装OpenSSL。安装时需要注意版本!!!
这块有点乱,先简单记录。要验证的话,可能需要结合Qt源码,以及Qt的bug来看才行
- Qt 从 5.2.0 起,不再官方支持 OpenSSL 低于 1.0.0 的版本。
- Qt 从 5.10起,官方二进制包开始使用OpenSSL 1.1
- Qt 从 5.12.4起,官方二进制包开始使用 OpenSSL1.1.1 的。
- Qt 从 6.2.0 起,开始支持 OpenSSL3.0(自己编译Qt)
- Qt 从 6.5.0 起,官方二进制包开始使用 OpenSSL 3.0。
简单说:
OpenSSL 3.0(Qt >= 6.5.0)
OpenSSL 1.1.x(Qt >= 5.10 Qt < 6.5.0)
OpenSSL 1.0.2(Qt < 5.10)
注: Qt 5.13起,在Windows下开始增加schannel作为ssl后端,可作为 openssl 的替代。Qt6.3起,编译Qt时,schannel插件已默认启用。如果不需要OpenSSL的扩展功能的话,新版本的Qt程序可以不用纠结OpenSSL的问题,使用Schannel就行。
其他
Git
Windows下安装的Git,会自带 openssl,这个东西功能不全,要避免使用。
钥yào yuè
密钥中的“钥”,读音争议很大 。
《现代汉语词典(第7版)》:【密钥】mìyuè (口语中多读mìyào)。
参考
- https://www.openssl.org/docs/man3.0/
- https://en.wikipedia.org/wiki/OpenSSL
- https://www.feistyduck.com/library/openssl-cookbook/online/
- https://blog.csdn.net/zhihao_li/article/details/131068038
- https://unix.stackexchange.com/questions/296697/how-to-encrypt-a-file-with-private-key