OpenSSL 数字签名
区别
| 私钥 | 公钥 |
---|
公钥私钥(如HTTPS实现) | 接收者解密时使用 | 发送者加密时使用 |
数字签名 | 签名者生成签名时使用 | 验证者验证签名时使用 |
谁持有密钥? | 个人持有 | 只要需要,任何人都可以持有 |
信息摘要
- 信息摘要:对数据进行处理,得到一段固定长度的结果,特点如下:
输出长度固定
:即输出长度和输入长度无关不可逆
:输出数据理论上不能推导出输入数据对输入数据敏感
:当输入数据变化极小时,输出数据也会发生明显的变化防碰撞
:不同的数据数据得到相同输出数据的可能性极低
- 场景:网络等传输后,通过摘要值,确定文件本身有没有发生变化
- openssl 支持摘要算法(即
openssl --help
输出的 Message Digest commands (see the dgst' command for more details)
信息):
-md4 to use the md4 message digest algorithm
-md5 to use the md5 message digest algorithm
-ripemd160 to use the ripemd160 message digest algorithm
-sha to use the sha message digest algorithm
-sha1 to use the sha1 message digest algorithm
-sha224 to use the sha224 message digest algorithm
-sha256 to use the sha256 message digest algorithm
-sha384 to use the sha384 message digest algorithm
-sha512 to use the sha512 message digest algorithm
-whirlpool to use the whirlpool message digest algorithm
$ openssl dgst -sha1 /etc/hosts
SHA1(/etc/hosts)= 0024556bbcb1584640ab4fb906a50e5ee4f88ddb
$ openssl sha1 /etc/hosts
SHA1(/etc/hosts)= 0024556bbcb1584640ab4fb906a50e5ee4f88ddb
$ sha1sum /etc/hosts
0024556bbcb1584640ab4fb906a50e5ee4f88ddb /etc/hosts
# debug 信息
$ openssl dgst -sha1 -d /etc/hosts
BIO[0x55e66ce720c0]: ctrl(6) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 0
BIO[0x55e66ce720c0]: ctrl(108) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 1
BIO[0x55e66ce720c0]: ctrl(10) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 0
BIO[0x55e66ce720c0]: ctrl(2) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 0
BIO[0x55e66ce720c0]: read(0,8192) - FILE pointer
BIO[0x55e66ce720c0]: read return 257
BIO[0x55e66ce720c0]: ctrl(10) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 0
BIO[0x55e66ce720c0]: ctrl(2) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 1
SHA1(/etc/hosts)= 0024556bbcb1584640ab4fb906a50e5ee4f88ddb
BIO[0x55e66ce720c0]: ctrl(1) - FILE pointer
BIO[0x55e66ce720c0]: ctrl return 0
BIO[0x55e66ce720c0]: Free - FILE pointer
# 输出二进制
$ openssl dgst -sha1 -binary /etc/hosts
# 输出十六进制
$ openssl dgst -sha1 -c -hex /etc/hosts
SHA1(/etc/hosts)= 00:24:55:6b:bc:b1:58:46:40:ab:4f:b9:06:a5:0e:5e:e4:f8:8d:db
数字签名
数字签名
分成两步:
- 首先对原始文件进行摘要运算,得到摘要值
- 然后使用公开密钥算法中的
私钥
对摘要值进行加密 - 用户通过
公钥
验证文件和签名是否匹配
在数字签名中,有 2 种行为:
- 生成消息签名的行为,两种生成和验证数字签名的方法:
- 直接对消息签名的方法(推荐)
- 对消息的散列值签名的方法
- 验证消息签名的行为
使用 openssl dgst
管理数字签名
$ openssl dgst --help
Usage: dgst [options] [file...]
file... files to digest (default is stdin)
-help Display this summary
-list List digests
-c Print the digest with separating colons
-r Print the digest in coreutils format
-out outfile Output to filename rather than stdout
-passin val Input file pass phrase source
-sign val Sign digest using private key
-verify val Verify a signature using public key
-prverify val Verify a signature using private key
-signature infile File with signature to verify
-keyform format Key file format (PEM or ENGINE)
-hex Print as hex dump
-binary Print in binary form
-d Print debug info
-debug Print debug info
-fips-fingerprint Compute HMAC with the key used in OpenSSL-FIPS fingerprint
-hmac val Create hashed MAC with key
-mac val Create MAC (not necessarily HMAC)
-sigopt val Signature parameter in n:v form
-macopt val MAC algorithm parameters in n:v form or key
-* Any supported digest
-rand val Load the file(s) into the random number generator
-writerand outfile Write random data to the specified file
-engine val Use engine e, possibly a hardware device
-engine_impl Also use engine given by -engine for digest operations
RSA 签名
- RSA 算法是一种非对称加密算法,与对称加密算法不同的是,RSA算法有两个不同的密钥
- 在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的
- 加密算法E和解密算法D也都是公开的
- 虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK
# 1. Create private/public key pair
openssl genrsa -out private.key 1024
# 2. Extracting Public key
openssl rsa -in private.key -out public.pem -outform PEM -pubout
# 3. Create hash of the data.
echo 'data to sign' > example.txt
openssl dgst -sha256 < example.txt > hash
# 4. Sign the hash using Private key to a file called hash.sign
openssl dgst -sha256 -sign private.key -out hash.sign hash
# 5. Verify the file (example.txt)and the digital signature (hash.sign)
openssl dgst -sha256 -verify public.pem -signature hash.sign hash
# 6. Verify the file (example.txt) by private key
openssl dgst -sha256 -prverify private.key -signature hash.sign hash
# 签名
openssl dgst -sha256 -sign private.key -sigopt rsa_padding_mode:pss -out signature.txt hash
# 验证
openssl dgst -sha256 -verify public.pem -sigopt rsa_padding_mode:pss -signature signature.txt hash
DSA 签名
DSA(Digital Signature Algorithm)
是一种数字签名的算法- 是由
NIST(National Institute of Standards and Technology,美国国家标准技术研究所)
于 1991 年制定的 数字签名规范(Digital Signature Standard,DSS)
- DSA 是 Schnorr 算法和 ElGamal 方式的变体,只能用于数字签名,不能进行加密解密
# 生成参数文件,类似于 DH 参数文件
$ openssl dsaparam -out dsaparam.pem 1024
# 生成密钥对,通过参数文件生成密钥对 dsaprivatekey.pem
$ openssl gendsa -out dsaprivatekey.pem dsaparam.pem
# 通过密钥对文件拆分出公钥
$ openssl dsa -in dsaprivatekey.pem -pubout -out dsapublickey.pem
# 查看私钥文件的信息,三个公共参数、公钥、私钥
$ openssl dsa -in dsaprivatekey.pem -text
# 查看公钥和文件的信息
$ openssl dsa -pubin -in dsapublickey.pem -text
# DSA 进行签名
$ openssl dgst -sha256 -sign dsaprivatekey.pem -out signature.txt hash
# 验证签名
$ openssl dgst -sha256 -verify dsapublickey.pem -signature signature.txt hash
ECDSA 签名
ECDSA(Elliptic Curve Digital Signature Algorithm)
是一种利用 椭圆曲线密码
来实现的数字签名算法- 相比 DSA 算法,ECDSA 算法安全性更高
- 在 ECDSA 中,有三个参数很重要:
- ECDSA 算法选择的命名曲线
- G,椭圆曲线的基点
- n,相当于 G 基点的打点操作,
n * G = 0
# 直接生成 ECDSA 私钥,不用预先生成 ECC 参数文件
$ openssl ecparam -name secp256k1 -genkey -out ecdsa_priv.pem
# 显示私钥信息
$ openssl ec -in ecdsa_priv.pem -text -noout
# 提取公钥
$ openssl ec -in ecdsa_priv.pem -pubout -out ecdsa_pub.pem
# 显示公钥
$ openssl ec -in ecdsa_pub.pem -pubin -text -noout
# 选择 sha256 作为 HASH 算法
$ openssl dgst -sha256 -sign ecdsa_priv.pem -out signature.txt example.txt
# 校验签名
$ openssl dgst -sha256 -verify ecdsa_pub.pem -signature signature.txt example.txt
Rabin
- Rabin 方式是由 M.O.Rabin 设计的公钥算法,利用了在 mod N 中求平方根的困难度。Rabin 方式可以被用于公钥密码和数字签名
总结
- DSA 签名算法运算比 RSA 签名运算慢很多,但是 ECDSA 签名算法比 RSA 签名生成快的多,ECDSA 签名验证却比 RSA 签名验证相对慢
- 从安全和速度综合考虑,在 DSA 和 ECDSA 中选一个,优先选择 ECDSA
扩展