GnuPG でファイルの暗号化・復号をやってみた

GnuPG、Gnu Privacy Guard、GPG というツールを試してみた。SSH Key とか SSL 証明書みたいな感じで、公開鍵と秘密鍵のペアを作って、データを暗号化したり署名を付けたりできるツールだ。元の仕様は OpenPGP というモノで、Pretty Good Privacy (PGP) というツールの別実装という位置付け。

エドワード・スノーデンが NSA の情報を暴露する際に、ジャーナリストに資料を送る時に GnuPG で暗号化したらしい。w

今回は Mac 上で試してみた。

# MacOS の Homebrew でインストールした
$ brew install gnupg pinentry-mac

$ gpg --version
gpg (GnuPG) 2.3.7
libgcrypt 1.10.1
Copyright (C) 2021 Free Software Foundation, Inc.
License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /Users/Neo/.gnupg
サポートしているアルゴリズム:
公開鍵: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
暗号方式: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256,
      TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256
AEAD: EAX, OCB
ハッシュ: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
圧縮: 無圧縮, ZIP, ZLIB, BZIP2

Homebrew の Forumula 名については、gpg2 などもエイリアスになっていることが公式ページで確認できる。

また、古い文献を参照すると gpg-agent というパッケージもインストールするような説明になっていたりするが、gpg-agent という Brew Formula は削除されている。現在は gnupg パッケージだけ導入すれば、最新版の gnupg には gpg-agent 相当のプログラムも同梱されているようだ。

それでは鍵ペアを作ってみよう。

# 鍵を作る
$ gpg --gen-key
gpg (GnuPG) 2.3.7; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

注意: 全機能の鍵生成には "gpg --full-generate-key" を使います。

GnuPGはあなたの鍵を識別するためにユーザIDを構成する必要があります。

本名: Neos21  # 名前を入力する
電子メール・アドレス: neos21@gmail.com  # メールアドレスを入力する
次のユーザIDを選択しました:
    "Neos21 <neos21@gmail.com>"

名前(N)、電子メール(E)の変更、またはOK(O)か終了(Q)? O  # O を入力
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。

# ココで TUI が起動し、パスフレーズを入力せよと出てくる
# そこそこの桁数で複雑なパスフレーズを入力しないと、同じ画面が何度も出てくる。警告メッセージなどがないので分かりにくい
# パスフレーズが通るともう一度入力を求められる

たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。
gpg: /Users/Neo/.gnupg/trustdb.gpg: 信用データベースができました
gpg: ディレクトリ'/Users/Neo/.gnupg/openpgp-revocs.d'が作成されました
gpg: 失効証明書を '/Users/Neo/.gnupg/openpgp-revocs.d/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   ed25519 2022-07-21 [SC] [有効期限: 2024-07-20]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid                      Neos21 <neos21@gmail.com>
sub   cv25519 2022-07-21 [E] [有効期限: 2024-07-20]

マシン内にある公開鍵・秘密鍵は -k-K オプションで確認できる。

# 公開鍵一覧を確認する・-k オプションでも同じ
$ gpg --list-keys
/Users/Neo/.gnupg/pubring.kbx
-----------------------------------
pub   ed25519 2022-07-21 [SC] [有効期限: 2024-07-20]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [  究極  ] Neos21 <neos21@gmail.com>
sub   cv25519 2022-07-21 [E] [有効期限: 2024-07-20]

# 秘密鍵は --list-secret-keys・-K で一覧表示できる
$ gpg --list-secret-keys
/Users/Neo/.gnupg/pubring.kbx
-----------------------------------
sec   ed25519 2022-07-21 [SC] [有効期限: 2024-07-20]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [  究極  ] Neos21 <neos21@gmail.com>
ssb   cv25519 2022-07-21 [E] [有効期限: 2024-07-20]
# `pub` と `sec` の部分が異なる

続いて、GPG の公開鍵を出力する。$ gpg -a --export 【名前】 > gpg-public-key.asc という感じでテキストファイルに書き出して扱えば良い。

# 公開鍵を出力する。コレを `Neos21.asc` などのファイル名で保存し公開すれば良い
# --armor = -a
$ gpg --armor --export Neos21
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEYtkLmRYJKwYBBAHaRw8BAQdA6abWqx/JF79lKP3o7pgcnffhHLBQ4GAa0MZp
... (中略) ...
XvfjAP0d096x7K9/RBQJHplw+kyaRhJ7OQhYnJcStg+jEi12CQ==
=EI1G
-----END PGP PUBLIC KEY BLOCK-----

いわゆる「公開鍵認証」方式なので、暗号化ファイルをやり取りする際は、

  1. 他人からもらった公開鍵を利用して暗号化し、
  2. 暗号化したファイルを相手に提供したら、
  3. 相手は「自分の秘密鍵」で復号する

という手順になるので、実際は暗号化を行う前に他人の公開鍵をインポートする作業が必要になる。

# 他人の公開鍵をインポートする
$ gpg --import ./someone-public-key.asc
# 秘密鍵も同コマンドでインポートでき、秘密鍵の場合は公開鍵も同時にインポートされる

今回はお試しなので、先程作った自分の公開鍵を使って、example.jpg という画像ファイルを暗号化してみる。

# ファイルを暗号化する : --recipient = -r ・ --encrypt = -e
$ gpg --recipient Neos21 --encrypt --armor ./example.jpg

  # インポートした公開鍵で暗号化する際、「信用 (trust)」確認が必要な場合がある
  $ gpg --edit-key 【公開鍵名】
  # → trust と入力し決定していく

# 暗号化したファイルは「元ファイル名.asc」で出力されている
$ cat ./example.jpg.asc
-----BEGIN PGP MESSAGE-----

hF4D8VZ2zYfN3B0SAQdAFTUkmIs82b69XujyDj72Rml2JHRGBaP1SJBRx09tC3Qw
/1z9wtqqQZGgMAJEegY2iZx/jlVQT7ZRHGogue7ZWvGqNm4NXY6EWG9atMeB5QPU
... (中略) ...
vRwpvzNKT7otZFEOSFaT344Arz8xZQwnq83yWqc=
=3Hme
-----END PGP MESSAGE-----

出力された example.jpg.asc というファイルは暗号化されており、一応テキストエディタで開ける。この辺は SSH Key や SSL 証明書なんかと同じような感じ。

こうして暗号化した example.jpg.asc ファイルに対し、正しい秘密鍵を当てることで、ファイルを復号して閲覧できるように戻してやる。

# 暗号化ファイルを復号する : --output = -o ・ --decrypt = -d
$ gpg --output ./example-out.jpg --decrypt ./example.asc
gpg: cv25519鍵, ID F15676CD87CDDC1D, 日付2022-07-21に暗号化されました
      "Neos21 <neos21@gmail.com>"

# 「OpenPGPの秘密鍵のロックを解除するためにパスフレーズを入力してください」という TUI が出てくる
# 秘密鍵を作った時に入力したパスフレーズを入力する
# 復号されたファイル `./example-out.jpg` が出力されている

こうして復号に成功すると example-out.jpg という画像ファイルが取り出せて、その内容は元の example.jpg と同一であることが確認できるであろう。

とりあえず以上。