Minisignでファイルへの署名や検証を行う

## 概要

- Minisignはシンプルに使える改竄防止のための署名・検証、そしてそれに必要な鍵データの生成等を行うツール
- OpenBSDで使われているsignifyと互換性があり暗号技術にEd25519を使用している
- 競合としてOpenPGPとその主要な実装であるGnuPGがあるが、それと比較してMinisignは単機能でシンプル

## Minisignとは

- Frank Denisが作ったファイル署名・検証のためのツール
- 競合のツールたちと比較して、シンプルに使えるのが特徴
- OpenBSDのsignifyと署名ファイルや鍵ファイルに関して互換性がある

## Minisignはどこで使われているか

- 例えばZig言語の配布物の署名に使われている
    - https://ziglang.org/download/
- 例えばMinIOの配布物の署名に使われている
    - https://dl.min.io/server/minio/release/linux-amd64/
- 例えばVyOSの配布物の署名に使われている
    - https://vyos.net/get/nightly-builds/
- 例えばHaikuOSの配布物の署名に使われている
    - https://download.haiku-os.org/nightly-images/x86_64/

もちろんMinisignの配布にもminisig署名されている
そのほかにもあるかもしれない
通常、署名ファイルは、署名したファイル名のsuffixに".minisig"が付与される

## Minisignの入手・インストール

2023年1月17日にリリースされたバージョン0.11が現時点(2024年7月)における最新版

公式サイトから各種OSで動作するバイナリパッケージが配布されている
- https://jedisct1.github.io/minisign/
    - macOS(Intel版/Apple silicon版両方対応)
    - Linux(ほぼ全てのLinux[x84_64/aarch64]対応)
    - Windows(x86_64のみ)

また、多くのディストリビューションやパッケージエコシステムでパッケージ配布されている

<a href="https://repology.org/project/minisign/versions">
    <img src="https://repology.org/badge/vertical-allrepos/minisign.svg" alt="Packaging status" align="right">
</a>

macOSの場合、Homebrewからのインストールは次のようにして行う
```shell-session:Homebrewでのインストール
$ brew install minisign
```

公式サイトからmacOS版バイナリをダウンロード・インストールは次のようにして行う
```shell-session:公式サイトからのダウンロード・解凍展開・インストール
$ wget https://github.com/jedisct1/minisign/releases/download/0.11/minisign-0.11-macos.zip
$ unzip minisign-0.11-macos.zip
$ cp -a minisign ~/bin/
$ chmod +x ~/bin/minisign
```

## minisignコマンドのオプション

```shell-session:minisignコマンドのオプション
$ minisign -v
minisign 0.11

$ minisign -h
Usage:
minisign -G [-f] [-p pubkey_file] [-s seckey_file] [-W]
minisign -R [-s seckey_file] [-p pubkey_file]
minisign -C [-s seckey_file] [-W]
minisign -S [-l] [-x sig_file] [-s seckey_file] [-c untrusted_comment]
            [-t trusted_comment] -m file [file ...]
minisign -V [-H] [-x sig_file] [-p pubkey_file | -P pubkey] [-o] [-q] -m file

-G                generate a new key pair
-R                recreate a public key file from a secret key file
-C                change/remove the password of the secret key
-S                sign files
-V                verify that a signature is valid for a given file
-H                require input to be prehashed
-l                sign using the legacy format
-m <file>         file to sign/verify
-o                combined with -V, output the file content after verification
-p <pubkey_file>  public key file (default: ./minisign.pub)
-P <pubkey>       public key, as a base64 string
-s <seckey_file>  secret key file (default: ~/.minisign/minisign.key)
-W                do not encrypt/decrypt the secret key with a password
-x <sigfile>      signature file (default: <file>.minisig)
-c <comment>      add a one-line untrusted comment
-t <comment>      add a one-line trusted comment
-q                quiet mode, suppress output
-Q                pretty quiet mode, only print the trusted comment
-f                force. Combined with -G, overwrite a previous key pair
-v                display version number

```

## minisignコマンドで秘密鍵と公開鍵を生成する

Minisignでの鍵生成はとても簡単で、ほとんど何も考えることはないです
GnuPGで、```gpg --expert --full-gen-key```をやることを想像して比べてみてください

```shell-session:鍵生成
$ minisign -GW
The secret key was saved as /Users/user1/.minisign/minisign.key - Keep it secret!
The public key was saved 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 RWQILkItspO1Ixjyv4jpeMgzxt35JfbY+aVE32BavUsZ9ZxRLvXNLhek

$ ls -l ~/.minisign/minisign.key 
-rw-------  1 user1  staff  262  7 18 16:12 /Users/user1/.minisign/minisign.key

$ ls -l minisign.pub
-rw-r--r--  1 user1  staff  113  7 18 16:12 minisign.pub

$ cat minisign.pub
untrusted comment: minisign public key 23B593B22D422E08
RWQILkItspO1Ixjyv4jpeMgzxt35JfbY+aVE32BavUsZ9ZxRLvXNLhek
```

- 上記のコマンド```minisign -GW```で、秘密鍵は```${HOME}/.minisign/minisign.key```に生成されます
- 同じく公開鍵は、上記コマンド実行時のカレントディレクトリに```minisign.pub```というファイル名で生成されます

もし秘密鍵を使うためにパスフレーズを必要とするようにしたい場合は、下記のようにやります

```shell-session:鍵生成(パスフレーズ設定)
$ minisign -G
Please enter a password to protect the secret key.

Password: 
Password (one more time): 
Deriving a key from the password in order to encrypt the secret key... done

The secret key was saved as /Users/user1/.minisign/minisign.key - Keep it secret!
The public key was saved 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 RWQWmyn3qxjq+mg+mFpRoWIsr+rZoYJGA5d7DW2qZ6gwOi36TPTaoQE2

```

## minisignコマンドでファイルに署名する

さて、肩の力を抜いて、とりあえずその辺のファイルにでも署名してみましょう
簡単ですから

```shell-session:署名する
$ dd if=/dev/urandom of=random.file bs=1m count=10  
10+0 records in
10+0 records out
10485760 bytes transferred in 0.029766 secs (352273063 bytes/sec)

$ minisign -Sm random.file 

$ ls -lh random.file*
-rw-r--r--  1 user1  staff    10M  7 18 16:32 random.file
-rw-r--r--  1 user1  staff   306B  7 18 16:32 random.file.minisig

$ cat random.file.minisig 
untrusted comment: signature from minisign secret key
RUT9wGP6QwBYqD5tg0lQ+5Web7EltRr58px3VgN3alJLDweqGG3FdyRHHuUKDfMkbPLqTZvtfFF+IWqhmQrLjw6IBCNALMWKAgo=
trusted comment: timestamp:1721287953	file:random.file	hashed
QreEvh8IyUenf2OBoedwY2luRstD0VzO1lSmUXqhVxqOPi9egZp4DXfHnbAm4hQu4OJhEu1Blpitkl9gjnIdBw==
```

- 上記では適当に作った10MBのファイルに対して、minisignコマンドで署名してみました
- 署名ファイルは、署名したファイルのファイル名に、suffixとして".minisig"が付与されたファイル名で生成されます


## 署名ファイルにメモを書き加える

- 署名ファイル(末尾が".minisig"のファイル)の一行目に、「untrusted comment:」というのがありますよね
- なんか信用できなさそうな文言のように感じるかもしれません

- でも便利なんですよ。この行は、後からいくらでもいじって良いということなのです
- つまり、署名によって改竄されていないことを証明する範囲が適用されない部分ということなのです
- ですから、署名したファイルに対するコメントとか、ファイルを署名とともに送る相手へのメッセージとか好きなようにコメントをつけたりすることができます
- なお、三行目の「trusted comment:」の部分は、いつ署名したかタイムスタンプ、署名したファイル名、ハッシュ値に署名したことについて署名しています

```shell-session:署名ファイルになにかいたずら書きでもしてみる
$ cat random.file.minisig 
untrusted comment: signature from minisign secret key
RUT9wGP6QwBYqD5tg0lQ+5Web7EltRr58px3VgN3alJLDweqGG3FdyRHHuUKDfMkbPLqTZvtfFF+IWqhmQrLjw6IBCNALMWKAgo=
trusted comment: timestamp:1721287953	file:random.file	hashed
QreEvh8IyUenf2OBoedwY2luRstD0VzO1lSmUXqhVxqOPi9egZp4DXfHnbAm4hQu4OJhEu1Blpitkl9gjnIdBw==

$ vi random.file.minisig

$ cat random.file.minisig
untrusted comment: blahblahblah
RUT9wGP6QwBYqD5tg0lQ+5Web7EltRr58px3VgN3alJLDweqGG3FdyRHHuUKDfMkbPLqTZvtfFF+IWqhmQrLjw6IBCNALMWKAgo=
trusted comment: timestamp:1721287953	file:random.file	hashed
QreEvh8IyUenf2OBoedwY2luRstD0VzO1lSmUXqhVxqOPi9egZp4DXfHnbAm4hQu4OJhEu1Blpitkl9gjnIdBw==
```

## minisignコマンドで署名とファイルを検証する

では、検証してそのファイルが改竄されていないことを確かめてみましょう

```shell-session:検証してみる
$ ls -l random.file*         
-rw-r--r--  1 user1  staff  10485760  7 18 16:32 random.file
-rw-r--r--  1 user1  staff       284  7 18 16:38 random.file.minisig

$ cat minisign.pub 
untrusted comment: minisign public key A8580043FA63C0FD
RWT9wGP6QwBYqG2HmgLpBueEcmun6iztjI07/TkeKaINywGbyu9E48se

$ minisign -Vm random.file -P RWT9wGP6QwBYqG2HmgLpBueEcmun6iztjI07/TkeKaINywGbyu9E48se
Signature and comment signature verified
Trusted comment: timestamp:1721287953	file:random.file	hashed

$ minisign -Vm random.file -p minisign.pub               
Signature and comment signature verified
Trusted comment: timestamp:1721287953	file:random.file	hashed
```

- 上記のように、検証に必要なのは次の3つです
    - ファイル本体
    - 署名ファイル
    - 公開鍵
- 公開鍵は、検証の際に公開鍵ファイルを指定する場合と、文字列として引数に指定する場合の2パターンあります


## 公開鍵の信用について

signifyもそうですが、Minisignも、そのツール自身には、公開鍵の信用を担保する仕組みがありません
そのため、公開鍵の運用によってその信用を担保することになります
多くの場合、下記のやり方を採用しているようです

- Webで公開されている配布物の検証をする場合は、多くの場合は、配布サイトに公開鍵の文字列を掲載していることが多いようです
- どうしてその方法で公開鍵の信用を担保できるのか。例えばGitHubのサイトに公開鍵を掲載した場合
    - GitHub自体が侵害された場合は、その公開鍵の信用は失われます
    - 配布者のGitHubアカウントが侵害された場合は、その公開鍵の信用は失われます
    - そうでない場合は、その公開鍵は信用できるはずです

## 終わり

- Minisignはシンプルなツールです
- 実装している機能が、署名と検証、鍵の生成だけのため、多くの人にとってわかりやすいと思います
- 公開鍵の信用については、運用方法によって担保する必要がありますが、今のところ自身の、あるいは信頼できるHTTPSサイトへ掲載するという方法をとっているケースが多いようです