Featured image of post Openssl再次学习

Openssl再次学习

第二次学习openssl,懂得的东西终于又变多了。

首先Openssl一般都是用来生成密钥的,它支持

  • 对称密钥算法:AES、DES、3DES、RC4、ChaCha20 等;
  • 非对称密钥算法:RSA、DSA、ECDSA、EdDSA 等;
  • 密码协议:TLS/SSL、DTLS、S/MIME、PKCS 等。

一个最简单的例子:

1
2
3
openssl genpkey -algorithm RSA -out key.pem #生成私钥
openssl req -new -key key.pem -out cert.csr #生成签名请求文件
openssl x509 -req -days 365 -in cert.csr -signkey key.pem -out cert.pem #响应请求签署证书

不知道你注意没有!我使用的 algorithm 而不是 cipher ,加密方法作为 OpenSSL 的核心,我们需要区分algorithm和cipher的区别,

algorithm和cipher的区别

算法(algorithm)和密码(cipher)是两个相关但不同的概念

algorithm通常指的是一种数学上的方法,用于加密和解密数据。例如,RSA、DSA、ECDSA、ECDH 等是一些常见的加密算法。

而cipher则是指的是具体的实现方式,包括加密算法、填充方式、运作模式等,比如 AES-256-GCM、AES-128-CBC、ChaCha20-Poly1305 等。

所以我们使用cipher指定具体的实现方式要更常见一点。

加密算法

只列举常见(或者略微 有名的)

对称加密算法

目前推荐AES-256,别的都不安全。

  • AES
  • Blowfish
  • Camellia
  • CAST5
  • IDEA
  • SEED
  • DES
  • Triple DES(3des)
  • RC4

Blowfish 和 Camellia 都是比较常见的对称加密算法(但是我们一般不用),而 CAST5 和 IDEA 相对来说已经被一些新的加密算法所取代,不再是主流的加密算法;SEED 是韩国政府推广使用的加密算法,但在国际上的应用并不广泛。后面几个则是安全有问题而不在使用了。

非对称加密算法

RSA家族:

  • RSA:基本的RSA加密算法。
  • RSA-PSS:RSA Probabilistic Signature Scheme,一种基于RSA的数字签名算法。
  • RSA-OAEP:RSA Optimal Asymmetric Encryption Padding,是基于RSA加密算法的一种填充方案数字签名算法。
  • RSA-KEM:RSA Key Encapsulation Mechanism,一种基于RSA的密钥交换算法。
  • RSA-CRT:RSA Chinese Remainder Theorem,一种优化RSA的计算方法(不属于签名算法或密钥交换算法)。

虽然家族成员很多,但是我们一般还是只使用rsa,因为它兼容性最好😂。

ECC家族:

支持的曲线类型包括 prime256v1、secp384r1 和 secp521r1 等。

  • ECDSA:(Elliptic Curve Digital Signature Algorithm) 基于椭圆曲线密码学的数字签名算法,(主要用于签名和验证,比如签发证书)。

  • EdDSA:(Edwards-curve Digital Signature Algorithm) 基于蒙哥马利曲线的数字签名算法,比ECDSA更高效,更安全(更多用于消息认证、数字签名)。

  • Ed25519:基于Curve25519的数字签名算法,比ECDSA更高效,更安全。(用于签名和验证,比如ssh)

  • ECDH:(Elliptic Curve Diffie-Hellman) 基于椭圆曲线密码学的密钥协商算法,用于生成共享密钥。

  • X25519:基于Curve25519的密钥交换算法,用于生成共享密钥。

  • X448:基于Curve448的密钥交换算法,用于生成共享密钥。

ecc家族里一般用的也挺花,ECDSA,EDDSA,Ed25519

DSA家族:

DSA家族只包含一种算法,即DSA本身。他的变种在ecc家族的ExDSA。

∵ 它的加解密速度比较慢,但对于数字签名等场景,其安全性较高。

∴ DSA更常用于数字签名,而RSA更常用于加密

哈希算法

  • MD5
  • SHA-1
  • SHA-2系列,如SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256
  • SHA-3系列,如SHA3-224、SHA3-256、SHA3-384、SHA3-512
  • BLAKE2系列,如BLAKE2s-128、BLAKE2s-160、BLAKE2s-224、BLAKE2s-256、BLAKE2b-160、BLAKE2b-256、BLAKE2b-384、BLAKE2b-512

md5和sha1已被证实不安全,一般sha3-256或者sha-256

提问:如果用ecc签名!为什么用ECDSA而不用Ed25519?

实际上,使用Ed25519算法作为数字证书的签名算法是可行的,因为Ed25519签名算法的安全性已经得到广泛认可。但是,Ed25519算法并不是所有软件和硬件都支持的,因此在实际应用中可能存在兼容性问题。而且在数字证书领域,目前使用最广泛的签名算法是RSA和ECDSA,而不是Ed25519。

创建理想的CA

首先你需要知道CA是什么!说白了!就是一个密钥对,首先就需要创建CA的私钥!这个至关重要!以后的在签发都是靠这个,所以必须要保存好。

1
openssl ecparam -out ca.key -name prime256v1 -genkey

这一步是创建私钥,默认就是ECDSA算法,-name 可以选择 prime256v1、secp384r1 和 secp521r1

除此之外,你要是不喜欢默认的ECDSA还可以选择EDDSA里面的ed25519,但是好像目前还没有多少使用ed25519来生成CA证书的。但是你要是喜欢尝鲜也是可以使用下面的命令来生成一个自己玩玩的。

1
openssl genpkey -algorithm ed25519 -out ca.key

为什么这次使用 genpkey 了呢,因为ed25519不是 椭圆曲线(Elliptic Curve) 而是 Edwards 曲线(Edwards Curve) 虽然师出同门ECC,但是不是一种曲线,只能算殊途同归吧。

genpkey也可以生成EC但是要指定curve类型(特指ECDSA)是prime256v1、secp384r1 还是 secp521r1。比较麻烦,还是推荐使用ecparam生成ECDSA。

1
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out ca.key

创建证书申请csr

自签这一步可以省略,但是如果需要签发SSL证书,这一步又绕不开,所以还是循规蹈矩,也创建csr申请,而且csr证书申请中又可以填写与私钥相对应的公钥和一些其他信息,如组织名、域名等。这样,证书机构就可以通过验证这些信息来保证证书的可信度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[ca]
preserve           = no
x509_extensions    = CA_DN
copy_extensions    = copy

[req]
prompt             = no
distinguished_name = CA_DN
utf8               = yes
req_extensions     = v3_ca

[CA_DN]
countryName             = US
stateOrProvinceName     = us
localityName            = us
organizationName        = us
organizationalUnitName  = us
commonName              = us
emailAddress            = [email protected]

[v3_ca]
subjectKeyIdentifier   = hash
basicConstraints       = critical,CA:true,pathlen:2
keyUsage               = keyCertSign,cRLSign
nsComment              = "US Signed ™"

把上面的基础配置复制到ca.cnf里面,接着再去发起CSR证书请求,命令如下:

1
openssl req -new -key ca.key -out ca.csr -config ca.cnf

req就是专门用来发起证书请求的,可以请求csr,也可以请求crt公钥哈。-new是根据输入的私钥新申请一个CSR证书请求。-config 就是使用我们上面写好的配置文件里面的信息。

根据CSR生成CRT(生成公钥)

X.509证书包含了公钥以及相关的证书信息,所以在这里就表示生成公钥。

1
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 -extensions v3_ca -config ca.cnf

这样一个简单的CA证书就签名好了。看看信息:

1
openssl x509 -in ca.crt -text -noout

签发SSL证书

创建私钥

这一步和上面没有啥区别,看个人心情来创建

1
2
mkdir ssl
openssl ecparam -out ssl/ssl.key -name prime256v1 -genkey

然后保存下面的内容到ssl.cnf里面

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[req]
prompt             = no
distinguished_name = ssl_DN
utf8               = yes
req_extensions     = ssl_ext

[ssl_DN]
countryName             = CN
stateOrProvinceName     = AnHui
localityName            = NanJing
organizationName        = TLS Inc
organizationalUnitName  = ssl
commonName              = *.jokeme.top #这里换成你需要保护的域名
emailAddress            = xyz@jokeme.top

[ssl_ext]
subjectKeyIdentifier = hash
basicConstraints     = CA:FALSE
subjectAltName       = @alt_names

[alt_names]
DNS.1 = *.jokeme.top #这里换成你需要保护的域名

发起CSR证书申请

1
openssl req -new -key ssl/ssl.key -out ssl/ssl.csr -config ssl.conf

签署证书(生成公钥)

1
openssl x509 -req -in ssl/ssl.csr -out ssl/ssl.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -extfile ssl.conf -extensions ssl_ext

无了!

shell脚本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/bash
# author : Frelon Lee
# Date   : 2023/04/12 12:54:27

writeCACnf() {
cat << EOF > conf/ca.cnf
[ca]
preserve           = no
x509_extensions    = CA_DN
copy_extensions    = copy
[req]
prompt             = no
distinguished_name = CA_DN
utf8               = yes
req_extensions     = v3_ca
[CA_DN]
countryName             = CN
stateOrProvinceName     = AnHui
localityName            = HeFei
organizationName        = CA
organizationalUnitName  = CA
commonName              = CA
emailAddress            = [email protected]
[v3_ca]
subjectKeyIdentifier   = hash
basicConstraints       = critical,CA:true,pathlen:2
keyUsage               = keyCertSign,cRLSign
nsComment              = "This is CA"
EOF
}

writeSSLCnf(){
cat << EOF > conf/ssl.cnf
[req]
prompt             = no
distinguished_name = ssl_DN
utf8               = yes
req_extensions     = ssl_ext
[ssl_DN]
countryName             = CN
stateOrProvinceName     = AnHui
localityName            = HeFei
organizationName        = SSL
organizationalUnitName  = SSL
commonName              = YYYYYYYY
emailAddress            = [email protected]
[ssl_ext]
subjectKeyIdentifier = hash
basicConstraints     = CA:FALSE
subjectAltName       = @alt_names
[alt_names]
DNS.1 = YYYYYYYY
DNS.2 = *.YYYYYYYY
EOF
}

geneCA(){
	openssl ecparam -out ca/ca.key -name prime256v1 -genkey
	openssl req -new -key ca/ca.key -out ca/ca.csr -config conf/ca.cnf
	openssl req -new -x509 -key ca/ca.key -out ca/ca.crt -days 3650 -extensions v3_ca -config conf/ca.cnf
}

geneSSL(){
	openssl ecparam -out ssl.key -name prime256v1 -genkey
	openssl req -new -key ssl.key -out ssl.csr -config $1/conf/ssl.cnf
	openssl x509 -req -in ssl.csr -out ssl.crt -CA $1/ca/ca.crt -CAkey $1/ca/ca.key -CAcreateserial -days 365 -extfile $1/conf/ssl.cnf -extensions ssl_ext
}


initENV() {
	echo "检查openssl环境..."
	x=$(openssl version | awk '{print $2}' | awk -F. '{print $1}')
	if [ $x -ge 1 ]; then
		echo -e "OpenSSL环境:\033[;32m通过\033[0m"
	else
		echo -e "OpenSSL环境:\033[;31m低于1.x的版本\033[0m"
		return 0
	fi
	echo ""
	echo "检测文件夹是否存在..."
	if [ -d "ssl/" -a -d "ca/" -a -d "conf/"  ]; then
		echo -e "检测结果:\033[;33m已存在\033[0m"
	else
		if [ ! -d "ssl/" ];then
			mkdir ssl
		fi
		if [ ! -d "ca/" ];then
			mkdir ca
		fi
		if [ ! -d "conf/" ];then
			mkdir conf
		fi
		echo -e "检测结果:\033[;32m不存在,已创建\033[0m"
	fi
	echo ""
	echo -e "检测配置文件..."
	if [ -f "conf/ca.cnf" -o -f "conf/ssl.cnf" ]; then
		echo -e "检测结果:\033[;33m存在配置文件\033[0m 是否保留?[y/n]:\c"
		read ipt
		if [ $ipt == "y" ]; then
			echo -e "执行结果:\033[;33m已忽略\033[0m"
		else
			rm -rfv conf/ca.cnf conf/ssl.cnf
			writeCACnf
			writeSSLCnf
			echo -e "执行结果:\033[;32m文件已重新创建\033[0m"
		fi
	else
		writeCACnf
		writeSSLCnf
		echo -e "检测结果:\033[;32m文件已创建\033[0m"
	fi
		echo ""
	echo "检测是否有其他CA证书..."
	if [ -f "ca/ca.key" ]; then
		echo -e "检测结果:\033[;31m存在其他CA密钥\033[0m 是否保留?[y/n]:\c"
		read selectNum
		if [ $selectNum == "n" ]; then
			rm -rfv ca/ca.key ca/ca.crt ca/ca.csr
			geneCA
			echo -e "执行结果:\033[;32m已生成新的CA密钥对\033[0m"
			openssl x509 -in ca/ca.crt -text -noout
		else
		echo -e "执行结果:\033[;33m已忽略\033[0m"
			return 0
		fi
	else
		geneCA
		echo -e "检测结果:\033[;32m已生成CA密钥对\033[0m"
		openssl x509 -in ca/ca.crt -text -noout
	fi
}

location=`pwd`
if [ $# == "1" ]; then
	if [ $1 == "init" ]; then
		initENV
	elif [ $1 == "help" -o $1 = "-h" -o $1 = "--help" ]; then
		echo "Script Verion: 0.0.1a"
		echo "首次执行:./cert.sh init "
		echo -e "申请证书:./cert.sh 'example.com'  \033[;35meg: ./cert.sh s.com\033[0m"
	else
		if [ -d "ssl/$1" ];then
			cd "ssl/$1"
		else
			mkdir "ssl/$1"
			cd "ssl/$1"
		fi
		sed -i "s/YYYYYYYY/$1/g" $location/conf/ssl.cnf
		geneSSL $location
		sed -i "s/$1/YYYYYYYY/g" $location/conf/ssl.cnf
		echo -e "执行结果:\033[;32m成功创建SSL证书\033[0m"
		openssl x509 -in ssl.crt -text -noout
	fi
else
	echo "Script Verion: 0.0.1a"
fi

这一次,又学了一遍openssl,我又写了个小脚本,方便生成和管理自签名的CA和SSL证书。

具体用法就是 ./cert.sh init 创建初始化环境,./cert.sh xx.com 创建ssl证书。默认的算法都是ECDSA,觉得不妥可以在脚本里面自己修改。