# 前言

一篇简单的 OpenSSL 散列使用经验,偶尔更新。


# 获取帮助

openssl dgst -h

输出如下:

Usage: dgst [options] [file...]
General options:
 -help               Display this summary
 -list               List digests
 -engine val         Use engine e, possibly a hardware device
 -engine_impl        Also use engine given by -engine for digest operations
 -passin val         Input file pass phrase source
Output options:
 -c                  Print the digest with separating colons
 -r                  Print the digest in coreutils format
 -out outfile        Output to filename rather than stdout
 -keyform format     Key file format (ENGINE, other values ignored)
 -hex                Print as hex dump
 -binary             Print in binary form
 -xoflen +int        Output length for XOF algorithms. To obtain the maximum security strength set this to 32 (or greater) for SHAKE128, and 64 (or greater) for SHAKE256
 -d                  Print debug info
 -debug              Print debug info
Signing options:
 -sign val           Sign digest using private key
 -verify val         Verify a signature using public key
 -prverify val       Verify a signature using private key
 -sigopt val         Signature parameter in n:v form
 -signature infile   File with signature to verify
 -hmac val           Create hashed MAC with key
 -mac val            Create MAC (not necessarily HMAC)
 -macopt val         MAC algorithm parameters in n:v form or key
 -*                  Any supported digest
 -fips-fingerprint   Compute HMAC with the key used in OpenSSL-FIPS fingerprint
Random state options:
 -rand val           Load the given file(s) into the random number generator
 -writerand outfile  Write random data to the specified file
Provider options:
 -provider-path val  Provider load path (must be before 'provider' argument if required)
 -provider val       Provider to load (can be specified multiple times)
 -propquery val      Property query used when fetching algorithms
Parameters:
 file                Files to digest (optional; default is stdin)

# 计算文件摘要

这是 openssl dgst 中最简单也是最常见的命令,例如计算一个文件的 SHA-256 摘要:

openssl dgst -SHA-256 _config.yml

此命令通过 SHA-256 散列算法计算当前工作目录下 _config.yml 文件的摘要,这是它的输出:

SHA2-256(_config.yml)= 10d90acf0a106d5258830937cf59bb8ecc3078c91efaecccd2212b9a8b93f98b

# 列出散列算法

OpenSSL 可以使用以下指令列出其支持的散列算法,根据版本而异:

openssl dgst -list

个人使用的 OpenSSL 是 3.1.2,它的输出如下:

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

# 散列算法简单介绍

# BLAKE2B-512

基于 Chacha20 的一种非常强大的散列函数,强度超过 SHA-2,接近 SHA-3,同时运行效率超过 SHA-3,输出为 512 位。

# BLAKE2S-256

基于 Chacha20 的一种非常强大的散列函数,强度超过 SHA-2,接近 SHA-3,同时运行效率超过 SHA-3,输出为 256 位。

# MD4

Ron Rivest 设计的一种散列函数,输出 128 位,已经被证明存在碰撞。

# MD5

Ron Rivest 设计的一种散列函数,输出 128 位,已经被证明存在碰撞。虽然非常常用,但是已经过时。

# SSL3-MD5

就是 MD5。

# MD5-SHA-1

一种双重散列,计算 MD5 值的 SHA-1 摘要以避免这两个算法各自的弱点。个人觉得不如 SHA-256,这个用法也不常见。

# MDC-2

基于分组密码的一种散列函数,输出取决于底层使用的分组密码。

# RIPEMD

基于 MD4 设计的一种散列算法,输出默认为 160 位,不常见,并且存在碰撞。

# RIPEMD-160

RIPEMD 的 160 位版本,也就是默认实现。

# RMD-160

就是 RIPEMD-160。

# SHA-1

NIST 发布的一个早期散列算法,输出为 160 位,极为常见,虽然安全性比 MD5 要高一些,但仍然存在碰撞和前缀冲突攻击。

# SSL3-SHA-1

就是 SHA-1。

# SHA-224

NIST SHA-2 散列算法标准之一,采用 SHA-256 不同的初始值并截断输出而来,输出 224 位。安全性强大。

# SHA-256

NIST SHA-2 散列算法标准之一,最为常见的散列函数之一,输出 256 位,安全性强大,常用于 HMAC、文件校验等。

# SHA-384

NIST SHA-2 散列算法标准之一,采用 SHA-512 不同的初始值并截断输出而来,输出 384 位,安全性强大。

# SHA-512

NIST SHA-2 散列算法标准之一,最为常见的散列函数之一,输出 512 位,安全性强大,常用于 HMAC、文件校验等。

# SHA-512-224

把 SHA-512 的输出截断为 224 位得到,常用于 HMAC。

# SHA-512-256

把 SHA-512 的输出截断为 256 位得到,常用于 HMAC。

# SHA-3-224

NIST SHA-3 散列算法标准之一,可用于替换 SHA-224,输出 224 位。SHA-3 通常被认为比 SHA-2 更安全。

# SHA-3-256

NIST SHA-3 散列算法标准之一,可用于替换 SHA-256,输出 256 位。SHA-3 通常被认为比 SHA-2 更安全。

# SHA-3-384

NIST SHA-3 散列算法标准之一,可用于替换 SHA-384,输出 384 位。SHA-3 通常被认为比 SHA-2 更安全。

# SHA-3-384

NIST SHA-3 散列算法标准之一,可用于替换 SHA-512,输出 512 位。SHA-3 通常被认为比 SHA-2 更安全。

# SHAKE-128

NIST SHA-3 散列算法标准之一,输出可扩展,默认 128 位。

# SHAKE-256

NIST SHA-3 散列算法标准之一,输出可扩展,默认 256 位。

# SM3

国密算法散列函数,输出 256 位,设计方面强度对标 SHA-256,安全性可靠,但并未经过广泛验证,使用场景有限。

# Whirlpool

一个基于大幅修改的 AES 结构的散列算法,输出 512 位,安全性非常强大。


# 输出选项说明

# -c

通过冒号,逐字节分隔 16 进制输出,两个十六进制数为一组,例如:

openssl dgst -SHA-256 -c _config.yml

输出如下:

SHA2-256(_config.yml)= 10:d9:0a:cf:0a:10:6d:52:58:83:09:37:cf:59:bb:8e:cc:30:78:c9:1e:fa:ec:cc:d2:21:2b:9a:8b:93:f9:8b

# -r

以 Coreutils 格式打印摘要,使其更容易与 GNU 工具集成,例如:

openssl dgst -SHA-256 -r _config.yml

输出如下:

10d90acf0a106d5258830937cf59bb8ecc3078c91efaecccd2212b9a8b93f98b *_config.yml

# -out outfile

将摘要输出到一个文件中,而非 stdout,例如:

openssl dgst -SHA-256 -out hash.txt _config.yml

摘要值将被输出到 hash.txt 文件当中。

# -keyform format

指定密钥文件格式,可以接受 PEM, DER, ENG 等格式,例如:

openssl dgst -SHA-256 -sign private_key.pem -keyform PEM -out signature,bin data.txt

# -hex

以 16 进制输出摘要,这个是默认行为,一般来说不加也是这样,例如:

openssl dgst -SHA-256 _config.yml

openssl dgst -SHA-256 -hex _config.yml

它们的输出一样:

SHA2-256(_config.yml)= 10d90acf0a106d5258830937cf59bb8ecc3078c91efaecccd2212b9a8b93f98b

# -binary

以二进制输出摘要,例如:

openssl dgst -SHA-256 -binary _config.yml

此时一般会看到一团乱码,因为它会尝试以 UTF-8 之类的字符集进行解析:

??mRX?7蟉粠?x?桃!+殝擓

可以尝试把它输出到文件:

openssl dgst -SHA-256 -binary -out hash.bin _config.yml

# -xoflen +int

对于可扩展输出函数(eXtendable-Output Functions),例如 SHAKE-128,SHAKE-256 等,指定其输出长度。

例如,这是默认的 SHAKE-128:

openssl dgst -SHAKE-128 _config.yml

它的输出为 128 位:

SHAKE-128(_config.yml)= 963197743bcc929737752110337fffd9

使用 xoflen +int 用户可以随意地调节它的输出字节数,对于 SHAKE-128 而言至多 32 字节(256 位),对于 SHAKE-256 而言至多 64 字节(512 位)。

例如,将输出调节为 24 字节(192 位):

openssl dgst -SHAKE-128 -xoflen 24 _config.yml

输出如下:

SHAKE-128(_config.yml)= 963197743bcc929737752110337fffd9662119d7a9b5c158

将输出调节为 32 字节(256 位):

openssl dgst -SHAKE-128 -xoflen 32 _config.yml

输出如下:

SHAKE-128(_config.yml)= 963197743bcc929737752110337fffd9662119d7a9b5c1589e93f9295bf8087a

# -d 或 -debug

输出 debug 信息,例如:

openssl dgst -SHA-256 -d _config.yml

输出为:

BIO[0x1fd3574d080]: ctrl(6) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 0
BIO[0x1fd3574d080]: ctrl(108) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 1
BIO[0x1fd3574d080]: ctrl(10) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 0
BIO[0x1fd3574d080]: ctrl(2) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 0
BIO[0x1fd3574d080]: read(0,8192) - FILE pointer
BIO[0x1fd3574d080]: read return 1 processed: 3814
BIO[0x1fd3574d080]: ctrl(10) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 0
BIO[0x1fd3574d080]: ctrl(2) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 1
SHA2-256(_config.yml)= 10d90acf0a106d5258830937cf59bb8ecc3078c91efaecccd2212b9a8b93f98b
BIO[0x1fd3574d080]: ctrl(1) - FILE pointer
BIO[0x1fd3574d080]: ctrl return 0
BIO[0x1fd3574d080]: Free - FILE pointer