scan4all 项目中的 minisign:文件签名与验签的极简安全方案全解析
【免费下载链接】scan4allOfficial repository vuls Scan: 15000+PoCs; 23 kinds of application password crack; 7000+Web fingerprints; 146 protocols and 90000+ rules Port scanning; Fuzz, HW, awesome BugBounty( ͡° ͜ʖ ͡°)...项目地址: https://gitcode.com/GitHub_Trending/sca/scan4all
导读
minisign 是一个"极简到极致"的文件签名与验签工具,它用一条命令完成密钥对生成、一条命令完成签名、一条命令完成验签,却内置了 Ed25519 数字签名、BLAKE2b 哈希与 scrypt 口令派生等完整的现代密码学能力。在 scan4all 项目中,aead.dev/minisignv0.2.0 作为间接依赖随 Go module 一起被 vendoring 进仓库(见 go.mod 与 vendor/modules.txt),其完整实现代码就位于 vendor/aead.dev/minisign/。读完本文,你将掌握 minisign 命令行工具的完整用法(生成密钥、签名、验签、恢复公钥)、全部 13 个命令行参数的语义,以及它的 Go 语言库级 API 与底层密码学原理,可以直接用于构建自己的软件分发签名校验流程。
一、minisign 是什么:Go 实现的极简签名工具
minisign 由 Andreas Auernhammer 用 Go 语言实现,是 Frank Denis 原始 C 实现的移植版本。它被设计为"dead simple"——只专注做三件事:
- 生成(Generate):创建一对公私钥;
- 签名(Sign):用私钥为文件生成签名文件;
- 验证(Verify):用公钥验证文件的签名是否有效。
它在设计上的关键决策是密钥对默认受口令保护:生成的私钥不是裸的 Ed25519 密钥,而是用用户口令经 scrypt 密钥派生后加密存储的密文,任何拿到私钥文件的人都无法直接使用,必须输入正确的口令。这种"私钥加密落地"的设计让 minisign 特别适合个人开发者签名发布软件包、脚本或配置文件的使用场景。
二、快速上手:三个命令完成全流程
minisign 的 CLI 使用体验非常直观,README 给出了完整的三步走示例(密钥生成 → 签名 → 验签),下面逐一展开。
第一步:生成密钥对(-G)
$ minisign -G Please enter a password to protect the secret key. Enter Password: Enter Password (one more time): Deriving a key from the password in order to encrypt the secret key... done The secret key was saved as ~/.minisign/minisign.key - Keep it secret! The public key was published as minisign.pub - That one can be public. Files signed using this key pair can be verified with the following command: minisign -Vm <file> -P RWSYKA736yqh+JrZ7cRDdWgck/WKtwW9ATBFmk8pQ1lHeUKXtV6uJ7Fu-G模式会交互式要求输入两遍口令来保护私钥,然后用 scrypt 从口令派生密钥并加密私钥。命令结束时:
- 私钥保存到
~/.minisign/minisign.key,必须保密; - 公钥保存到当前目录的
minisign.pub,可以公开分发; - 终端会直接打印出"用该密钥对验签"的标准命令,公钥以 Base64 字符串形式内嵌其中(
-P参数),方便你拷贝到任何机器上立即验签,无需携带公钥文件。
第二步:签名文件(-S)
$ minisign -Sm message.txt Enter password: Deriving a key from the password in order to decrypt the secret key... done-S表示签名(Sign),-m message.txt指定待签名文件。由于私钥是加密存储的,这一步需要输入生成密钥对时设置的口令,程序会解密私钥、计算文件签名并写出默认的签名文件message.txt.minisig。
第三步:验证签名(-V)
$ minisign -Vm message.txt Signature and comment signature verified Trusted comment: timestamp:1614718943 filename:message.txt-V表示验签(Verify),-m message.txt指定待验证文件。验证通过后输出两行信息:
- 第一行确认文件签名与comment 签名双双验证成功;
- 第二行展示签名中携带的 trusted comment——这里可以看到 minisign 默认在签名里自动嵌入的时间戳与文件名,用于审计"这个签名是什么时候、针对哪个文件生成的"。
如果文件在签名后被篡改过,验证会失败并给出明确报错。
三、命令行完整参考:四种模式与全部参数
README 给出了 minisign CLI 的完整语法,整理如下。
语法总览
Usage: minisign -G [-p <pubKey>] [-s <secKey>] minisign -S [-x <signature>] [-s <secKey>] [-c <comment>] [-t <comment>] -m <file>... minisign -V [-H] [-x <signature>] [-p <pubKey> | -P <pubKey>] [-o] [-q | -Q ] -m <file> minisign -R [-s <secKey>] [-p <pubKey>]四种操作模式
| 模式 | 参数 | 说明 |
|---|---|---|
| 生成 | -G | 生成一对新的公钥/私钥 |
| 签名 | -S | 使用私钥为文件签名 |
| 验签 | -V | 使用公钥验证文件签名 |
| 恢复 | -R | 从私钥重新生成公钥文件 |
全部参数详解
| 参数 | 作用 | 默认值 |
|---|---|---|
-m <file> | 要签名或验证的文件 | 必填 |
-o | 配合-V使用,验证通过后将文件内容输出到标准输出 | 关闭 |
-H | 配合-V使用,要求对"预哈希后的文件"进行验签 | 关闭 |
-p <pubKey> | 指定公钥文件路径 | ./minisign.pub |
-P <pubKey> | 直接以 Base64 字符串形式传入公钥 | 无 |
-s <secKey> | 指定私钥文件路径 | $HOME/.minisign/minisign.key |
-x <signature> | 指定签名文件路径 | <file>.minisig |
-c <comment> | 添加一行非受信注释 | 空 |
-t <comment> | 添加一行受信注释 | 时间戳+文件名 |
-q | 安静模式,抑制输出 | 关闭 |
-Q | 极简安静模式,配合-V仅打印受信注释 | 关闭 |
-f | 配合-G或-R,覆盖已存在的公钥/私钥文件 | 关闭 |
-v | 打印版本信息 | 关闭 |
其中两个细节值得特别说明:
-p与-P是互斥的:-p指定公钥文件路径,-P直接内嵌公钥的 Base64 文本。后者正是上面"生成密钥对"输出中那条验签命令所用的形式,适合在没有公钥文件的场景下快速验签。
-c与-t的信任语义截然不同(对应源码中的UntrustedComment与TrustedComment,见 signature.go):
-t指定的受信注释会被签名,验签时若被篡改则验证失败,可以安全信任;-c指定的非受信注释不参与签名,任何人可以改它而不破坏签名,绝不能作为信任依据。
四、安装:预编译二进制与源码构建两种方式
README 提供了两种安装路径。
方式一:使用预编译二进制
minisign 为 Windows、Linux、macOS 三大平台发布预编译产物,官方 README 中以 v0.1.2 为例列出的构建矩阵如下:
| 操作系统 | 架构 | 发行包 |
|---|---|---|
| Linux | amd64 | minisign-linux-amd64.tar.gz |
| Linux | arm64 | minisign-linux-arm64.tar.gz |
| macOS | arm64 | minisign-darwin-arm64.tar.gz |
| macOS | amd64 | minisign-darwin-amd64.tar.gz |
| Windows | amd64 | minisign-windows-amd64.zip |
下载对应平台的压缩包解压后即可直接使用,无需任何运行时依赖。注意:这里列的发行版号以官方 release 页面的最新 tag 为准,本文引用的仓库中 vendoring 的版本为 v0.2.0(见 go.sum)。
方式二:从源码构建(Go 1.16+)
如果你的系统已安装 Go 1.16 及以上版本,可以一条命令从源码构建:
git clone https://aead.dev/minisign && cd minisign go build -o . aead.dev/minisign/cmd/minisign构建产物就是当前目录下的minisign可执行文件。这与 scan4all 仓库中对该模块的 vendoring 方式一致——aead.dev/minisign以独立 Go module 的身份被引入并固化在 vendor/ 目录下,构建时不需要联网拉取。
五、作为 Go 库使用:签名验签的最小代码
除了命令行工具,minisign 还暴露了完整的 Go 语言库 API,只需要一行 import:
import "aead.dev/minisign"README 给出了一个完整的库级示例:生成密钥对 → 签名 → 验签的闭环。
package main import ( "crypto/rand" "log" "aead.dev/minisign" ) func main() { var message = []byte("Hello World!") public, private, err := minisign.GenerateKey(rand.Reader) if err != nil { log.Fatalln(err) } signature := minisign.Sign(private, message) if !minisign.Verify(public, message, signature) { log.Fatalln("signature verification failed") } log.Println(string(message)) }这个示例覆盖了库的四个核心 API:
| API | 签名 | 作用 |
|---|---|---|
GenerateKey(random io.Reader) | func GenerateKey(random io.Reader) (PublicKey, PrivateKey, error) | 用熵源生成公私钥对,random传nil时使用crypto/rand.Reader(见 minisign.go) |
Sign(private PrivateKey, message []byte) []byte | func Sign(privateKey PrivateKey, message []byte) []byte | 对消息签名,返回可传输的签名文本(含默认注释) |
Verify(public PublicKey, message, signature []byte) bool | func Verify(publicKey PublicKey, message, signature []byte) bool | 验证签名,返回布尔结果 |
GenerateKey生成的公钥/私钥 | PublicKey/PrivateKey类型 | 分别实现crypto.PublicKey与crypto.Signer接口 |
底层库还提供了更多进阶 API,例如:
SignWithComments/Reader.SignWithComments:自定义受信与非受信注释;Reader流式签名验签:边读取边计算哈希,支持对超长文件(无法整体载入内存)做HashEdDSA预哈希签名,也能对同一消息的前缀片段生成快照签名(见 minisign.go);PublicKeyFromFile/PrivateKeyFromFile(password, path)/SignatureFromFile:从文件加载密钥与签名(见 public.go、private.go、signature.go)。
六、底层原理:读懂 minisign 的密码学设计
结合 vendor/aead.dev/minisign/ 下的源码,可以完整还原 minisign 的密码学实现细节。
6.1 签名算法:Ed25519 + BLAKE2b
minisign 的签名算法基于 Ed25519(包注释与EdDSA uint16 = 0x6445常量可见于 minisign.go):
EdDSA(0x6445):直接对完整消息签名,用于能整体放入内存的文件;HashEdDSA(0x4445):先对消息做 BLAKE2b-512 哈希再签名,用于无法载入内存的大文件(配合 CLI 的-H参数与库的Reader流式接口)。
验签时对HashEdDSA签名会自动先对消息做blake2b.Sum512再交给 Ed25519 验证(见 minisign.go)。因此两种算法产出的签名在验签端是透明兼容的。
6.2 双签名机制:消息签名 + 注释签名
每次签名实际上会产生两个 Ed25519 签名(见 minisign.go):
msgSignature = Ed25519(私钥, 消息):对消息本体签名;commentSignature = Ed25519(私钥, msgSignature || trustedComment):对"消息签名 + 受信注释"拼接结果再签名。
由此在验签时得到两层保证:消息未被篡改,且受信注释(如时间戳、文件名)是真实可信的。而非受信注释只是签名文件第一行的纯文本前缀,不参与任何签名计算。
6.3 签名文件格式
签名是纯文本的四行结构,由Signature.String()方法生成(见 signature.go):
untrusted comment: <非受信注释> <Base64(2字节算法 || 8字节KeyID || 64字节消息签名)> trusted comment: <受信注释> <Base64(64字节注释签名)>解析时(UnmarshalText)严格校验四行结构、算法标识(只允许EdDSA/HashEdDSA)、各段长度以及注释前缀,任何一项不合法都会返回错误(见 signature.go)。
6.4 密钥格式与私钥加密(scrypt + 异或流加密)
公钥的文本格式为一行注释加一行 Base64:2字节算法 || 8字节KeyID || 32字节Ed25519公钥(见 public.go)。其中的 64 位KeyID由公钥本身经 BLAKE2b-256 哈希后取前 8 字节小端序得到(见 minisign.go),用于在验签时快速定位候选公钥。
私钥落地时经过口令加密,格式为固定 158 字节:2字节算法 || 2字节scrypt标识(0x6353) || 2字节blake2b标识(0x3242) || 32字节随机盐 || 8字节scrypt ops || 8字节scrypt mem || 104字节密文(见 private.go)。加密流程(见encryptKey,private.go):
- 明文 = 8 字节 KeyID ‖ 64 字节 Ed25519 私钥(共 72 字节);
- 计算完整性标签
tag = BLAKE2b-256(0x6445 || 明文); - 用
scrypt(口令, 盐, N, r, p)派生 104 字节密钥流; - 密文 = (明文 ‖ tag) ⊕ 密钥流。
解密时反向异或出明文与标签,用常量时间比较(subtle.ConstantTimeCompare)校验标签,防止针对口令的侧信道攻击(见 private.go)。默认的 scrypt 成本参数ops=33554432、mem=1073741824对齐 libsodium 的OPS_LIMIT_SENSITIVE/MEM_LIMIT_SENSITIVE,且设有上限(0x2000000ops、0x40000000mem)防止恶意构造的密钥文件拖垮验签端(见 private.go)。
6.5 签名确定性
minisign 的签名是确定性的:PrivateKey.Sign不需要也不使用随机源(io.Reader参数被忽略),相同消息 + 相同私钥永远产出相同签名(见 private.go)。这归功于 Ed25519 签名算法本身的确定性设计,便于签名结果的重复比对与审计。
七、在 scan4all 中的定位与延伸阅读
在本仓库中,aead.dev/minisign以 v0.2.0 作为间接依赖出现(go.mod),源码被完整 vendoring 到 vendor/aead.dev/minisign/(包含minisign.go、private.go、public.go、signature.go与 LICENSE、README)。这类签名库在安全工具链中的典型用途是:校验外部下发的 PoC 模板、指纹规则或漏洞库更新包是否来自可信发布方、是否在传输中被篡改——这正是 minisign 设计的核心场景。
如果你想进一步实践,可以在 scan4all 的 Go 代码中直接以aead.dev/minisign包为依赖,参考上文第五节的最小示例,把"验签"逻辑接入到项目读取外部规则文件的入口处;日常验证第三方下发的文件签名,则直接使用第三节的 CLI 命令即可。
结语
minisign 的价值在于用最少的命令数封装了完整且现代的密码学栈:Ed25519 提供抗篡改的数字签名,BLAKE2b 提供高速哈希与密钥 ID 派生,scrypt 提供抗暴力破解的口令保护,双签名机制让"受信注释"真正可信。无论是独立命令行使用,还是像 scan4all 这样将其作为 Go 依赖嵌入自己的安全工具链,minisign 都提供了一个简单、可审计、开箱即用的文件签名方案。
参考文件索引
- 官方文档主体:vendor/aead.dev/minisign/README.md
- 核心实现(签名/验签/流式接口):vendor/aead.dev/minisign/minisign.go
- 私钥加密与解密实现:vendor/aead.dev/minisign/private.go
- 公钥解析与序列化:vendor/aead.dev/minisign/public.go
- 签名格式定义与解析:vendor/aead.dev/minisign/signature.go
- 依赖声明:go.mod、go.sum、vendor/modules.txt
【免费下载链接】scan4allOfficial repository vuls Scan: 15000+PoCs; 23 kinds of application password crack; 7000+Web fingerprints; 146 protocols and 90000+ rules Port scanning; Fuzz, HW, awesome BugBounty( ͡° ͜ʖ ͡°)...项目地址: https://gitcode.com/GitHub_Trending/sca/scan4all
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考