对网络下载文件通常有两种校验手段:
- 用哈希算法计算文件摘要值,以校验文件的完整性(防篡改)。
- 用发布者的公钥对文件签名验签,以校验文件来源(防伪造)。
相关术语
- PGP(Pretty Good Privacy):优良保密协议,最初指用来加密的商业软件的名字
- OpenPGP:与最初 PGP 工具兼容的 IETF 开放标准,当前的"PGP"通常指此标准
- GnuPG:是 OpenPGP 协议的一种完备的实现,此外还提供了完整的秘钥管理,和实现了许多协议中可选的加密、压缩算法
- 通常 Linux 发行版有内置,Mac 下安装:
brew install gpg,手动下载地址
- 通常 Linux 发行版有内置,Mac 下安装:
- OpenSSL:用 C 实现 SSL/TLS 协议的个开源的加密函式库
完整性校验
哈希(Hash)是指将不定长度数据映射成固定长度的函数,通过它可以取到数据的摘要信息,常见的哈希算法有 SHA256、MD5等;以 Linux/Ubuntu 为例,可在终端执行compgen -c | grep sum查看本机安装有哪些哈希工具(Windows下是Get-Filehash和certutil.exe -hashfile):
$ compgen -c | grep sum
sha1sum
sha256sum
md5sum
sha512sum
# ...
# 通常在文件下载页会有对应的哈希值,拷贝下来校验:
echo "0e2801e47fb1b92d2743204fcf650ce2fcad1a13ef7a44fe05738101a383e4a2 php-8.3.4.tar.gz" | sha256sum --check
# 校验通过时提示如下:
php-8.3.4.tar.gz: OK
签名校验
签名是指发送方用私钥对数据的摘要加签,接受方用发送方的公钥解签,并对用同样哈希算法取摘要值验证;发送方将自己的公钥发布到公钥服务器,接收方通过公钥指纹下载对应的公钥,再通过公钥和签名文件来验签,确保下载的文件是符合预期的。
# 先查看验签所需的密钥指纹(签名文件和目标文件放在同一目录下)
gpg --verify php-8.3.4.tar.gz.asc
# 输出:
gpg: assuming signed data in 'php-8.3.4.tar.gz'
gpg: Signature made Tue 12 Mar 2024 11:44:25 PM UTC
gpg: using EDDSA key C28D937575603EB4ABB725861C0779DC5C0A9DE4
gpg: Can‘t check signature: No public key
# 1. 根据公钥指纹在公钥服务器上搜索公钥
gpg --search-keys 'C28D937575603EB4ABB725861C0779DC5C0A9DE4'
# 输出:
gpg: data source: https://keys.openpgp.org:443
(1) Jakub Zelenka <bukka@php.net>
256 bit EDDSA key 1C0779DC5C0A9DE4, created: 2021-04-10
# 2.1 通过KeyID将公钥导入到本地
gpg --receive-keys 1C0779DC5C0A9DE4
# 2.2 再用检查一下秘钥指纹确保下载下来的公钥是符合预期的(和官网提供值对比)
gpg --fingerprint 'C28D937575603EB4ABB725861C0779DC5C0A9DE4'
# 3. 验签
gpg --verify php-8.3.4.tar.gz.asc
# 校验通过时输出:
gpg: assuming signed data in 'php-8.3.4.tar.gz'
gpg: Signature made Tue 12 Mar 2024 11:44:25 PM UTC
gpg: using EDDSA key C28D937575603EB4ABB725861C0779DC5C0A9DE4
gpg: Good signature from "Jakub Zelenka <bukka@php.net>" [full]