Openssl
什么是Openssl
OpenSSL 是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。
基本功能
openssl是一个开源程序的套件、这个套件有三个部分组成:
- libcryto,这是一个具有通用功能的加密库,里面实现了众多的加密库;
- libssl,这个是实现ssl机制的,它是用于实现TLS/SSL的功能;
- openssl,是个多功能命令行工具,它可以实现加密解密,甚至还可以当CA来用,可以让你创建证书、吊销证书。
密钥算法类型及密钥编码
密钥算法类型
目前主要包含两种密钥算法类型:
- 对称机密算法:加密和解密时使用相同的密钥
- 非对称加密算法:加密密钥与解密密钥成对出现,一般为私钥和公钥。私钥用于签名或加密;公钥用于验签或解密。
对称机密算法目前主要包括:AES,DES,3DES;非对称加密算法主要包括RSA,ECC。
密钥编码及后缀
编码格式
- PEM:Privacy Enhanced Mail,打开看文本格式,以"-----BEGIN…"开头, "-----END…"结尾,内容是BASE64编码.
- DER:Distinguished Encoding Rules,辨别编码规则 (DER) 可包含所有私钥、公钥和证书。它是大多数浏览器的缺省格式,并按 ASN1 DER 格式存储。它是无报头的,PEM 是用文本报头包围的 DER。
PEM 转 DER: openssl x509 -in cert.crt -outform der -out cert.der
DER 转 PEM: openssl x509 -in cert.crt -inform der -outform pem -out cert.pem
注:其中x509是密码学里公钥证书的格式标准,要转key,将x509改为rsa等。
文件后缀名
- CRT:certificate,常见于*NIX系统,有可能是PEM编码,也有可能是DER编码,大多数应该是PEM编码;
- CER:certificate,还是证书,常见于Windows系统,同样的,可能是PEM编码,也可能是DER编码,大多数应该是DER编码;
- KEY:通常用来存放一个公钥或者私钥,并非X.509证书,编码同样的,可能是PEM,也可能是DER;
- CSR:Certificate Signing Request,即证书签名请求,这个并不是证书,而是向权威证书颁发机构获得签名证书的申请,其核心内容是一个公钥(当然还附带了一些别的信息),在生成这个申请的时候,同时也会生成一个私钥;
- PFX/P12:predecessor of PKCS#12, 包含了私钥与公钥证书,私钥采用密码保护,对ngnix服务器来说,一般CRT和KEY是分开存放在不同文件中的,但Windows的IIS则将它们存在一个PFX文件中。
- JKS:Java Key Storage,这是Java的专利,跟OpenSSL关系不大,利用Java的一个叫"keytool"的工具,可以将PFX转为JKS,当然了,keytool也能直接生成JKS,不过在此就不多表了.
PKCS
PKCS类型,即公钥密码学标准,可参考:维基百科-公钥密码学标准
类型 | 名称 | 简介 |
---|---|---|
PKCS#1 | RSA密码编译标准(RSA Cryptography Standard) | 定义了RSA的数理基础、公/私钥格式,以及加/解密、签/验章的流程 |
PKCS#8 | 私钥消息表示标准(Private-Key Information Syntax Standard) | Apache读取证书私钥的标准 |
PKCS#10 | 证书申请标准(Certification Request Standard) | 参见RFC 2986。规范了向证书中心申请证书之CSR(certificate signing request)的格式 |
PKCS#12 | 个人消息交换标准(Personal Information Exchange Syntax Standard) | 定义了包含私钥与公钥证书(public key certificate)的文件格式。私钥采密码(password)保护。常见的PFX就履行了PKCS#12 |
对称加密算法
对于对称加密算法,主要集中在对openssl的使用上,可以先看一下帮助文档:
$ openssl enc -h
unknown option '-h'
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-cbc-hmac-sha1 -aes-128-cbc-hmac-sha256
-aes-128-ccm -aes-128-cfb -aes-128-cfb1
-aes-128-cfb8 -aes-128-ctr -aes-128-ecb
-aes-128-gcm -aes-128-ofb -aes-128-xts
-aes-192-cbc -aes-192-ccm -aes-192-cfb
通过输入密码,进行加密
# password from stdin
$ openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass
# password from cmd line
$ openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass pass:123456
# password from file
$ openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass file:passwd.txt
# password from enviroment
$ openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass env:passwd
# password from fd
$ openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass fd:1
- 对称加密的使用中,虽然我们输入了-pass,指定了密码,但是本质是采用key和iv向量进行加密的,我们输入的-pass,会转换成key和iv
- 为了增强安全性,在把用户密码转换成 key / iv 的时候需要使用盐值,默认盐值随机生成。使用-S参数,则盐值由用户指定。也可指用-nosalt指定不使用盐值,但降低了安全性,不推荐使用。
- 因为本质是采用 key / iv 加密,所以我们可以直接用 key / iv 解密或者加密
手动指定Key和IV值,指定key / iv 后,-pass参数不起作用
$ openssl enc -aes-128-cbc -in plain.txt -out encrypt.txt -K 1223 -iv f123 -p
非对称加密算法
RSA
算法原理
暂不详解,参考:RSA算法探秘
密钥生成
- OpenSSL明文生成命令如下:
## generate private key without password
$ openssl genrsa -out rsa.key 2048
## export public key
$ openssl rsa -in rsa.key -pubout -out rsa.pub
- 明文私钥内容如下:BEGIN RSA PRIVATE KEY为PKCS#1格式
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArzMYu9B07EwgLma0c+BK+vGAGrVqvRnhxPr4o7NVAfCqKe6V
7evym0ClkCK4NJ7s8bHJjmTxBXIpZuPOJBJhG2H0EALFap7sfzSxbbHIUkoJDO/c
kuo7enZ/R5UIs/esuua5/oiPlx3XY/9+OHviuyCtCPy0dFi7j9TNxstsUj7eXs+Y
r1TC+bA7CointNqi9TDwU3cM74jdgUrIU/uLtqL2mB22RCa80FfcURp7tQYVDyPO
nHex4ijjjyl1zi26YI1kxZf8dRlRoFfGTayrS/8Txp0KqGKEsLJyYQ8DeuEhW9gW
/Ka340ZC7ObVMqTzMJ7pzxyWmbRqHOIlO54jxQIDAQABAoIBAB2gHEyWAU97x+1Q
vK7jfIpWj/z0NGppl/3BGo5D4toDIiMZDw0+WrXaBqUK2e87+IEeOSD0/LSZC1s0
pkT/PqBsveJ/NXbEDOWtuVr9NwyDLGidnsTRCuG4a+lk0CXueazZGxZpbS52g1eL
eoJ+oGZYLipY4QLThlPZ/jnhaB238CfAQ+KfkkxdJcPEJWzONalWsTrb0RK+0WHZ
sgwJwCn9zBECZYNkHKKV0G1/TOyslZTZwo8aXCsEtwQmtwqtuYEaPCTrJ8YPpjoD
HjEdt6sUcCJd98aHxJ9zuABgDlq7NZAsAhgmdPPcnXu5xSFgFw7yPj/6UDgZxtcb
5VkSMsECgYEA2a9nKL241eMnqJ9/dBE84fNFEg0C9hNEljGr8sxilg0cs3nk4v6P
GRVcl6fjmRm6bIUzHPmFFFBOzr9JIlKv71II1S1Dn4l0gIuT5epPB1OlinBCU+Ur
jjhuZ3UOeZQ3LF9nKeDqn6jDjY6jXCQRK9xqKmzZ2yCUGrwYKpa0JskCgYEAzgla
B+y5bWPLYC0sv76yz5I+yTfIl7PAO6clgzSgBhHNFkjPA0eWcA/AA9tZS5Nz5MB5
ACiKN82dmnOedkkpJg29CTc7KttNTie5A7n+reKKV8qMMSM7I/MbQn/j7GIrW/uG
6WiZveXtK7o4jLZOGPE2nTx0iFGrrUjLK3TURx0CgYAdD3J5GOLNAvcvZqOQLiDv
lRdacow7p5TXbCglUK20lGmJeDNbLlqSIazrvgj/TlT52cpaCuF+Nb5fkV/FCj7c
dxogw1ssuB/qbTfAUMheFQebdKMWKhjncpcijpjxGB1Jei7+gz0vNUtt4WXjjhkQ
vusZYNCwlSfQbd3YCahhKQKBgC/xeSOy8AsGV8LPgEQ2CcHHVBjahDDYwPigklgP
nNUMu15eHt2ygM0evR2oowS1ERi/uOhShqcpj2zrTopTx+F0/PHyCjCUy05Oa/z0
ANFRj8OR/EFK424gGc3FmLHevhwvUVtq3auUnzW3pYUIvu+K4ZyA/tThvEMcVzqL
ewH5AoGBAKx3QRwdnCYFZTV26DO1LqjT3b2AbGBtM18u2mPwf593qJt3oJdJMGii
LGkGNZgCm88gMN/sY+chSJumlCHToFHLiovVIManpkv0Y7sXHw6TUeSjg5hB84b6
If/YzYcoFIpi1uKGVMSTnEdzLx1sjqM00qsVZz9cz8f71TMOOsQx
-----END RSA PRIVATE KEY-----
- 公钥内容如下:BEGIN PUBLIC KEY为PKCS#8格式
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArzMYu9B07EwgLma0c+BK
+vGAGrVqvRnhxPr4o7NVAfCqKe6V7evym0ClkCK4NJ7s8bHJjmTxBXIpZuPOJBJh
G2H0EALFap7sfzSxbbHIUkoJDO/ckuo7enZ/R5UIs/esuua5/oiPlx3XY/9+OHvi
uyCtCPy0dFi7j9TNxstsUj7eXs+Yr1TC+bA7CointNqi9TDwU3cM74jdgUrIU/uL
tqL2mB22RCa80FfcURp7tQYVDyPOnHex4ijjjyl1zi26YI1kxZf8dRlRoFfGTayr
S/8Txp0KqGKEsLJyYQ8DeuEhW9gW/Ka340ZC7ObVMqTzMJ7pzxyWmbRqHOIlO54j
xQIDAQAB
-----END PUBLIC KEY-----
- OpenSSL密文生成命令如下:
## generate rsa private key with password
$ openssl genrsa -aes256 -out name_private.key 2048
- 密文如下:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,6BD39B13ECA6BE46F418ECC341EEC626
p4TtCgJUP7Ik/f2xqJrJ3zfbGiA49T3Vrf9naKSYrZawGVhqYxRu+fiXePxKc25L
8rdnwCiF7x2xtR9uNWcWlFIe76KlPqrFMqBzVrEloOb0bM9TvZ06ZsYE6DrlH2xj
1NLzKz9I3CQ9M/VZIHInzvm7J1vFPFwSH5NSjq3oIVnMgfPMzaq5DCBYIxJ4nOEm
fGRx9bXnTzpIPCR6MrgmZiWzEt3akgkKSzQlfEEOLWfjEDBvJmuLO20CIfj+Q8Y6
rTMroud7sZb+FFDHAB3BolEp2Bqfi0YQJ8rMKTl+On3QFdBQD+v9jcTurqhD1C47
3KHieg18ZN2OxNTHHJMo0A1VEent6lvBSHIPKtgyUBP87+nUPsWoBDQV+zoL3pCP
O4zlY35WEt6BU+ImupkNNjZ70Sgfr3hUdXN3ZZi2rWUqGABzUpBREF9UuQVuqOeO
lpswWKMKQIXuvbZ70OdZ6JsUBMdeEIZSvEDeez85ef2GwuB6IvJtxmWNf4POiJxJ
oNponrYCh6RatQLDKgg0iqE2fkyq6QoKN8mFIHNwG7LS5CsSCiNzsj1lhl4pm2eB
5NQrInKa/sDFN1uFmtrWGw1bhyJdUPGPhaw5Xb1DRh1dbxooieEaCysuu+RpZpqc
AVwhrKf2IB2N82mEiQfD0FwJ4FGtBhlAmtMHHjtlDmbh1qzOYs1wUKpPY8C72fza
XwfS8kMdac3HWJc4osJ+/YoQv9cQtQX/DwiA/86nxRiogjbtDYERneu2ucxnzFrV
i0l9frX2qvkuXWArlT9+0zFZA3fTF0fP5j2mrf8tdTE+OdAVqRW50l2JiVId8qUv
2D5ygiHn1h+zPreeckA1386HMYwPirHcr/JpzrI5R+hCgXGEVi2GQISRjsVa2sqS
hNEirQFe7M6HPgtPaXcjKm/R8MY2aVHI3irTccXvIjDo2GCb85ZQFLqdQOE3N+h7
xrdcDaNZV6K6ZcudUsLiiH6gjXeiTL9VeSJQdyJ5mDJpEl9297JU7CbrRwndUgTV
qJ6Q5s9r158Bb0aLQwYFx0FEwqIiQB+tZoJ1e9+H8jNuRvDn35thMrOw+QcsMsT8
7QHL741jjcB51610afi5Zb2xhUKiWwrJLLKfp+e+4B3aFnhBm8anRcwBaYaF4OWK
4O8vialNxUelI6qJqyjb9sS/9G+YCmWjkvO/Wc7CcZ2dag0cxvyV+XZllUfFaZpN
5KbIH+zv+6pa2GyeePWekvsYQstXB43lKDYYjcO89SVGwEXGw1W7TlJI9SPZl3eR
FcN/O7CEcZfA17XDsS7u6FZgLfRlLeqSpRhRxgAuB7XpdwKVazPc6fVr48h6rH/M
Po9+wDUId7wrdAnxZgETpcIVgISpszfCYGKuYc1tZXaBDZxivHCV4oTdDp9uFwF1
QB6kZIcQ2evqDLtQt5jRNHl7792RNiwWIZd66WTV2fie2YHoF42lhj7/AdbI+nDx
Wzt0bvV5/lwsrnSZbLLTGwdxs/eoDrhhuCBeChoeXsxwm0yCu7cy8Ogqv/LXu5m8
Nm7HkkZ0eldHiFhOiRSDRCfzJwCBmZt6wPnvgsslBwYA8MCN5qI2a3nxMz5rxip/
-----END RSA PRIVATE KEY-----
- 其他命令
## view the public key
$ openssl rsa -pubin -in name.pub -noout -text
## remove the password of the private key
$ openssl rsa -in name.key -out name_plain.key
## view private key with interactive mode
$ openssl rsa -in name.key -noout -text
## view private key with a password file
$ openssl rsa -in name.key -noout -text -passin file:path/to/password
## convert from PKCS#8 to PKCS#1
$ openssl rsa -pubin -in name.pub -RSAPublicKey_out
## convert from PKCS#1 to PKCS#8
$ openssl rsa -RSAPublicKey_in -in name.pub -pubout
## encrypt with private key, actually with public key
$ openssl rsautl -encrypt -in plain.txt -inkey -inkey name.key -out enc.txt
## decrypt with private key
$ openssl rsautl -decrypt -in enc.txt -inkey name.key -out replain.txt
## encrypt with public key
$ openssl rsautl -encrypt -in plain.txt -inkey name.key -pubin -out enc1.txt
## sign with private key
$ openssl rsautl -sign -in plain.txt -inkey name.key -out sign1.txt
## verify with public key
$ openssl rsautl -verify -in sign1.txt -inkey name.key -pubin -out replain1.txt
密钥分析
PKCS#1
RSA私钥的PKCS#1的PEM格式如下:
-----BEGIN RSA PRIVATE KEY-----
BASE64 ENCODED DATA OF RSAPrivateKey
-----END RSA PRIVATE KEY-----
私钥结构如下:其中比较重要的都是与RSA算法相关的整数。
RSAPrivateKey ::= SEQUENCE {
version Version, //版本
modulus INTEGER, // RSA合数模 n
publicExponent INTEGER, //RSA公开幂 e
privateExponent INTEGER, //RSA私有幂 d
prime1 INTEGER, //n的素数因子p
prime2 INTEGER, //n的素数因子q
exponent1 INTEGER, //值 d mod (p-1)
exponent2 INTEGER, //值 d mod (q-1)
coefficient INTEGER, //CRT系数 (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
首先,我们可以通过以下Go代码将PEM格式的私钥转换为DER格式的字节串,并解析为可用于分析的私钥结构体:
func getPrivKey(keyFile string) (*rsa.PrivateKey, error) {
key, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
block, _ := pem.Decode([]byte(key))
if block == nil {
return nil, fmt.Errorf("failed to decode pem data")
}
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
fmt.Println(priKey.N.Bytes()) // 模数N
eBytes := make([]byte, 8)
binary.BigEndian.PutUint64(eBytes, uint64(priKey.E)) // 公有幂,一般为65537
fmt.Println(eBytes)
fmt.Println(priKey.D.Bytes()) // 私有幂
fmt.Println(priKey.Primes[0].Bytes()) // n的素数因子p
fmt.Println(priKey.Primes[0].Bytes()) // n的素数因子q
fmt.Println(priKey.Precomputed.Dp.Bytes()) //值 d mod (p-1)
fmt.Println(priKey.Precomputed.Dq.Bytes()) //值 d mod (q-1)
fmt.Println(priKey.Precomputed.Qinv.Bytes()) // CRT系数 (inverse of q) mod p
return priKey, nil
}
或者也可以通过ASN.1 JS Decoder对DER进行分析,为了方便,我们直接采用第二种方式分析,如下:
其中,模数N部分如下,其他类似:
a. 02: tag
b. 82 – 81: 代表长度用1byte表示,82代表长度用2byte表示(此字节部分tag后不存在)
c. 0101: length 2bytes表示
d. 00: 在modulus数据前添加00,原因未知,请知情道友告知。
e. 模数N
PKCS#8
RSA私钥的PKCS#8的PEM格式如下
-----BEGIN PRIVATE KEY-----
BASE64 ENCODED DATA OF PrivateKeyInfo
-----END PRIVATE KEY-----
私钥结构如下:
PrivateKeyInfo ::= SEQUENCE {
version Version,
algorithm AlgorithmIdentifier,
PrivateKey BIT STRING
}
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
PKCS#1与PKCS#8互转参考:PKCS#1 <=> PKCS#8
ECC
算法原理
暂不详解,参考:ECC椭圆曲线加密算法
曲线类型
目前主要有如下曲线,其中曲线secp256k1在区块链中使用较为广泛。
$ openssl ecparam -list_curves
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
密钥生成
本节仅介绍secp256k1的生成,其他曲线类似
- OpenSSL明文生成命令如下:
# generate secp256k1 private key
$ openssl ecparam -name secp256k1 -genkey -out secp256k1-key.pem
# export public key
$ openssl ec -in secp256k1-key.pem -pubout -out ecpubkey.pem
- 生成的私钥内容如下:
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIO/oTB61Jef6zBanUeWXUmyHIKQE6RCKuriskrNfee3AoAcGBSuBBAAK
oUQDQgAEBgmGjRWN+oZwehgqEmalK6YtMPgC/m1nkUE+YTymDp3sJ4L+VIAF7mrN
gPimd79cG37U2bn41bZIjGS2qXVjUA==
-----END EC PRIVATE KEY-----
- 生成的公钥内容如下:
-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE1xy6i/50bcje4mrDWIGL729DDdHFtCz9
t4VCfr8KP5WyLH5+0FPB4qnwhVOrpg2CZi3UVOW44+hGqQke2eeURQ==
-----END PUBLIC KEY-----