當我們要進行機密文件傳輸時,可能會面臨許多不同的傳輸方式,但是過程中必須確保資訊安全,因此你就會需要考量到許多因素。這篇文章我打算分享如何利用 GPG 工具對檔案進行簽章與加密,檔案無論透過任何方式傳送給對方,都只有明確指定的對象可以開啟檔案,藉此達到資訊安全的中的機密性(Confidentiality)與完整性(Integrity)要求。
資訊安全 (Information security) 有三個重要的核心概念,分別是機密性(Confidentiality)、完整性(Integrity) 與可用性(Availability),簡稱 CIA!當我們在考量「檔案傳輸」的安全性時,有好幾種不同的安全層級可以考量。若是透過網路進行檔案傳輸,你肯定會想到使用 TLS 傳輸層安全性協定,透過 TLS 可以確保傳輸過程的機密性與完整性,但若透過 USB 離線傳輸呢?此時你就無法確保這兩點了!因此我們會需要更好的工具來達成資訊安全的目的,這裡我將介紹如何用 GPG 這套工具。
簡介 GPG (GnuPG)
基本上 GPG (GNU Privacy Guard) 源自於 PGP (Pretty Good Privacy),當初是為了能夠提供更安全的電子郵件傳輸所設計的一套加解密工具。但是 PGP 是一套商用軟體,為了能夠提供大眾另一套開源且自由的選擇,因此先發展出了 OpenPGP 標準,並制訂 RFC4880 標準規格,接著就實作出了 GPG 這套工具,它不但能支援對 E-mail 進行加密,也能對任何數位檔案進行加密(encrypt)、解密(decrypt)、簽章(sign)、驗章(verify)等處理。GPG 是一組 CLI 命令列工具,可以很容易的跟其他應用程式整合,例如 Git 或 Outlook 就經常使用,也支援 S/MIME 與 Secure Shell (ssh) 等應用。
我們從維基百科的 GNU Privacy Guard 文章,可以看到關於 GPG 的完整歷史沿革,建議大家可以先抽空看過。在我先前的 如何使用 GPG (GnuPG) 對 Git Commit 與 Tag 進行簽章 文章中,也曾經介紹過 GPG 這套工具。
在 Linux 或 macOS 作業系統底下,幾乎都已經內建 GPG 工具。但是很有可能是 gpg1
的舊版,你可以用 gpg --version
查詢目前的 gpg
(GnuPG) 版本是否在 2.x 以上,以及工具支援的產生金鑰的演算法(Pubkey)、加密演算法(Cipher)、雜湊演算法(Hash)與壓縮演算法(Compression)等等。
# gpg --version
gpg (GnuPG) 2.2.29-unknown
libgcrypt 1.9.3-unknown
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: /c/Users/user/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2
如果你是 Windows 使用者的話,你只要安裝 Git for Windows 就會內含 gpg
命令列工具,不過你還要特別設定 PATH
環境變數才能方便的使用 C:\Program Files\Git\usr\bin\gpg.exe
工具。以下是我認為修改 PATH
使用者環境變數最安全的方法,直接使用 SetEnv 命令列工具來修改比較不會弄亂現有環境變數。
# 先用 PowerShell 下載設定環境變數的利器 SetEnv(你也可以手動下載)
Invoke-WebRequest -Uri "https://github.com/doggy8088/SetEnv/releases/download/1.0/SetEnv.exe" -OutFile "SetEnv.exe"
# 增加 PATH 使用者環境變數(這段命令支援 PowerShell 也支援 Command Prompt 環境)
SetEnv.exe -ua PATH %"C:\Program Files\Git\usr\bin"
Gpg4win 還附有一個 GUI 介面的 金鑰管理員(Kleopatra) 與 Outlook 外掛程式,你可以用來收發 PGP/MIME 郵件,需要的人還是可以自行安裝。
GPG 的運作原理
GPG 為了要能做到機密性(Confidentiality)的要求,我們要確保發送端(Sender)到接收端(Receiver)之間的關係不能有其他第三人會看到「明文」內容,因此 PGP 使用到一系列雜湊演算法、資料壓縮演算法、對稱金鑰演算法與公鑰加密演算法來完成加密任務。
要瞭解 GPG 的運作原理,就要先瞭解他的祖先 Pretty Good Privacy 的設計結構,我們可以從下圖來剖析 PGP 的加解密過程:
這個過程非常巧妙的完成訊息的安全傳輸,當你需要將文件發送給 100 個人的時候,雖然你需要取得這 100 人的公開金鑰,但加密的時候,也只需要將你的「明文」資料加密一次而已,大幅的提高加解密的效率! 👍
使用 GPG 加解密檔案,並不需要依賴複雜的 PKI 基礎建設,但雙方依然都要先各自產生 GPG 金鑰組(key-pair),並且「接收端」要先匯入「發送端」的「公開金鑰」,並先設定「信任」對方的身份,這是建立兩方「信任傳輸」的基礎,非常重要!
每台電腦的 GPG 工具都會維護著一份 GPG Keychain (鑰匙圈),在匯入金鑰時,這些金鑰都會匯入到 GPG Keychain 之中,每一把金鑰會需要設定信任等級,用以識別這些金鑰的信任程度。
無論匯入的金鑰是否受信任,都不影響金鑰的效力(validity of the key),只要金鑰匯入到你的電腦,金鑰的「有效性」是一定會檢查的。
想像一下,你如果是「接收端」,預計接收一個「發送端」傳來的檔案,你如何「相信」這個檔案沒有被竄改?從 GPG 的角度來看,你要先「匯入對方的公開金鑰」到你的電腦,然後用這把金鑰解密檔案。但是你取得「發送端」的「公開金鑰」過程安全嗎?沒人知道!只有你能確認這件事,對吧?!所以從工具的角度來看,他是無法識別金鑰的「可信程度」,只有「你」可以「標註」這個金鑰的「信任程度」或「信任等級」!
GPG 在設定金鑰信任時會區分以下幾種信任等級:
-
絕對信任 (Ultimate)
這個只會用在自己擁有的金鑰,任何訊息用這把金鑰簽章過的,都會被視為可靠的。
想像一下,你從朋友那邊拿到一把金鑰,你對這把金鑰進行簽章處理,這個簽章的結果對你來說依然是信任的,因為哪是你自己用 絕對信任(Ulitmate) 的金鑰簽署的,即便這把金鑰並沒有設定信任等級。
-
完整信任 (Full)
這個等級只會用來設定信任簽署其他人的金鑰。
舉個例子,如果張三的金鑰被你的好友李四簽署過,而李四的金鑰已經匯入到你的 GPG Keychain 中,並且設定為 完整信任 (Full),那麼這份被李四簽署過的金鑰,也就是張三的金鑰),就是受信任的。這就是一個信任鍊的關係!
你應該在確實驗證與簽署過李四的金鑰之後,才能將李四的金鑰設定為完整信任清單中 (Full ownertrust)!
-
未知對象 (Unknown)
任何金鑰在匯入 GPG Keychain 之後,預設就是 Unknown
信任等級。
這意味著這把金鑰並不在預設的信任清單(ownertrust)中,也就是說,這把金鑰是不受信任的!
-
未定義 (Undefined)
這個等級與 Unknown
幾乎一樣,但又有點不太一樣,因為這個 Undefined
等級是一個被你明確宣告這是「未知對象」的狀態。
通常這個狀態代表你想要在日後才要找時間來確認這把金鑰的信任等級。
-
從未信任 (Never)
這個信任等級幾乎等同於 Unknown
與 Undefined
,這個層級的金鑰一樣是不可信任的。
這個 Never
等級是一個被你明確宣告這是「確定不信任」的狀態。
-
無名小卒 (Marginal)
這個 Marginal
有微不足道的意思,簡單來說就是「不重要」的金鑰。你要用 3 把以上 Marginal
等級以上的金鑰簽署過的金鑰,才能視為是一把「有效的」金鑰。
舉個例子,如果你把張三、李四、王五的金鑰設定為 Marginal
信任等級,而且這三位都願意簽署老六的金鑰,那麼老六的金鑰就是有效的。因為這種用法過於複雜,基本上不建議這樣使用!
有了上述完整的知識基礎,接下來就可以好好的應用 GPG 在實務的情境中了。
建立 GPG 金鑰組(key-pair)
請使用 gpg --full-generate-key
建立全新的金鑰組,先擁有一個金鑰組才能對訊息進行數位簽章(Digital Signature)。建立的過程中,若遇到需要選擇的地方而又不知道該如何選擇,採用預設值通常就是比較安全的設定:
- 你要選擇金鑰的用途,預設是加密與簽章都會使用。
- 金鑰的長度決定了加密的強度,建議選預設值即可。
- 金鑰的有效期限,可以有效避免金鑰外洩的風險,但預設是不會過期。
- GnuPG 需要替金鑰給予一個「身份」識別的 User ID,你必須輸入 Real name 與 Email address 才能建立金鑰,而 Comment 欄位可以自己選擇要不要輸入。
- 最後要替你的金鑰設定一組 Passphase (密碼)
$ gpg --full-generate-key
gpg (GnuPG) 2.2.4; Copyright (C) 2017 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.
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection?
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Requested keysize is 3072 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N)
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Will Huang
Email address: will@example.com
Comment:
You selected this USER-ID:
"Will Huang <will@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key C22DCF85C7B99245 marked as ultimately trusted
gpg: directory '/home/will/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/will/.gnupg/openpgp-revocs.d/138711BA41E360645F37E23CC22DCF85C7B99245.rev'
public and secret key created and signed.
pub rsa3072 2020-05-04 [SC]
138711BA41E360645F37E23CC22DCF85C7B99245
uid Will Huang <will@example.com>
sub rsa3072 2020-05-04 [E]
從產生金鑰的訊息中你會發現有以下這段:
gpg: key C22DCF85C7B99245 marked as ultimately trusted
預設從本機產生的金鑰,預設都會自動標示 絕對信任!
注意:若要信任特定人所簽署的訊息,就要匯入特定人的公開金鑰,並調整信任層級才行。
對訊息進行簽章
建立 GPG 金鑰組之後,就可以開始對訊息進行簽章,以下我示範幾個比較長見的 gpg
命令:
-
建立明文簽章
這種類型的簽章,主要針對「文字訊息」進行簽章,而且輸出的內容也是「純文字」格式。
以下是將 test
這四個字進行明文簽章的結果:
echo "test" | gpg --clearsign
第一次簽章會需要輸入你的私密金鑰的 Passphase (密碼):
注意:輸入完正確的密碼後,GPG 會自動啟動一個 gpg-agent
背景程序,暫時記憶你剛剛輸入的密碼,所以在短時間內不需要再次輸入密碼。
密碼輸入正確就會將訊息(test
)進行簽章,並輸出類似以下的內容:
❯ echo "test" | gpg --clearsign
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
test
-----BEGIN PGP SIGNATURE-----
iQGzBAEBCAAdFiEEPa6gkcpWHS5IKpVBcsfm1hMB+TMFAmJ7RWwACgkQcsfm1hMB
+TPPCwv7B7zxRgzz/jisqGXF7VlWk0BZ3g4W3OR564Wslt58n0EQN4uCqCB2gRtZ
DEgRXYH1pYcEFde8/8xmiWKBgyONmFgeNDgyRhWMfsSsm5pFmFwBwWgQO3mDGIpG
HRAtvDWZESt44We1ffZsTTlzjouzjlOx+o3qFLT6+wHKUASGRCJtajOfGmYQbx/X
0DlsLV5L6pOuNrfZyvtkrstanPWGX6EHPvvS4kddSVaNuiIqiXDLNPnlZWQ5jjae
oxwaYEazcu/rvc1LIA83lVMElUC0AFAwOUbfPm+sZQ/xNcqhyvx65uJbzZo/FoWf
GuF32ejbyccGyAbZ5X9rMpo76ers5RvfAeJreHTgxz8oOeAIjlxthfW9DBTTFjm+
6qe/Fb00s7kcVP7jg7weFQUXMF8lq7io4XFc6PvV8tVVC3gNbcWSlgzB6qgQcahF
P+DuBEku8glCY3tewwK4cwsrtdPr+si7WHsgm4ETl+SLLbkpTOn5LO6CDNsRGpzb
8MhUfos9
=KbWy
-----END PGP SIGNATURE-----
這裡的 --clearsign
代表你想建立一個「明文」的簽章,其結果會包含原本的訊息內容,並附上簽章資料!
如果我們想把簽章的結果輸出到一個檔案,可以這樣執行:
echo "test" | gpg --output test.txt --clearsign
注意:簽章後的結果,是跟原始訊息內容放在一起的,但是這種類型的!
不過,如果是在 Linux (包含 WSL2 環境) 或 macOS 的 Shell 環境下,就可能會出現以下錯誤:
will@DESKTOP-K3PI2H2:~$ echo "test" | gpg --clearsign
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
test
gpg: signing failed: Inappropriate ioctl for device
gpg: [stdin]: clear-sign failed: Inappropriate ioctl for device
或是這個錯誤:
error: gpg failed to sign the data
fatal: failed to write commit object
要能成功對訊息進行簽章,你必須事先設定好 GPG_TTY
環境變數,才能正常使用。由於每次登入都需要這個環境變數,所以建議將這段命令加入到你 Shell 的啟動檔之中。
-
使用 Bash 的人,請將以下命令加入到你的 ~/.profile
檔案中
export GPG_TTY=$(tty)
-
使用 Zsh 的人,請將以下命令加入到你的 ~/.zprofile
檔案中
export GPG_TTY=$(tty)
-
使用 Fish 的人,請將以下命令加入到你的 ~/.config/fish/config.fish
檔案中
set -x GPG_TTY (tty)
🔥 這個步驟非常重要,而且只需要設定一次,你可以透過 man gpg-agent
得知這個注意事項,初學者蠻容易忽略的。我今天在設定 WSL 的時候,就是遺漏了這個步驟,導致鬼打牆好久!
少數 macOS 用戶可能還是會遇到上述設定還是無法成功對訊息簽章的狀況,那麼建議你加裝 pinentry-mac 工具,其設定步驟如下:
brew upgrade gnupg # 這個步驟可能會花些時間
brew link --overwrite gnupg
brew install pinentry-mac
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
killall gpg-agent
-
建立壓縮的簽章
雖然說簽章的內容是固定大小,但是連同內容本身可能還是會占空間,因此 GPG 有提供「壓縮簽章」的版本。
我們想對這個檔案進行簽章處理,其命令如下:
gpg -o test.sig --sign test.txt
注意:gpg
的用法是 gpg [options] [command] [files]
,所以 -o test.sig
要放在命令的前方!
我以一個大小 1MB
的文字檔 test.txt
進行簽章處理,最後產生的 test.sig
簽章檔大小約略只有 2121 bytes
而已,由於這是一份壓縮過的檔案,所以你是看不出原始內容的。但其實這份簽章檔內容有包含未加密過的原始訊息內容喔,這點必須特別注意! 🔥
-
建立獨立的簽章檔 (Detached signatures)
有時候將「訊息內容」與「簽章內容」放在同一個檔案裡面並不方便,因為我們可能還是希望能夠開啟該檔案,所以 gpg
提供另一個 --detach-sig
命令,可以將「簽章內容」放在另一個獨立檔案中,如此一來就相當實用了! 👍
gpg -o test.sig --detach-sig test.txt
這個命令會產生一個只有簽章的 test.sig
檔案,這個檔案一樣是壓縮過的內容,但沒有包含原始訊息內容。我以一個 1MB
的文字檔 test.txt
來簽章,這一個 test.sig
簽章檔只有 438 bytes
而已,非常的小!(壓縮過)
-
建立文字格式的獨立簽章檔 (Detached signatures)
這裡我要先介紹 ASCII-Armor 這個專有名詞。
早期 PGP (Pretty Good Privacy) 使用來當作安全的 E-mail 傳輸之用,而傳送 E-mail 的時候不允許使用二進位格式的內容來傳輸,所有二進位的檔案內容最終都要編碼成文字型態才能使用。然而,我們要將郵件內容加密,勢必會需要將加密過的郵件內容轉成文字格式,而當時這個轉換功能就被稱為 ASCII-Armor!
因此,GPG 也提供了一個 --armor
或 -a
選項,可以讓你輸出一個「文字格式」的簽章檔內容,命令如下:
gpg -o test.sig --armor --detach-sig test.txt
其輸出的 test.sig
檔案內容如下:
-----BEGIN PGP SIGNATURE-----
iQGzBAABCAAdFiEEPa6gkcpWHS5IKpVBcsfm1hMB+TMFAmJ7atgACgkQcsfm1hMB
+TOGHAv+N8b8YVzhDZqkB7UGcDehNdv+aaGaoCe2N04u69O1RL/nVRyv3yxcvA/F
zoVoNP83oTw8kAtjabD5E5ngWWalcQsZSAYUnCmkLjWy5cSUSZPn8Bbd/AKVzhnh
siRm4Xrh8uc6HH5bIX6bQ67pJ/iBhKzT7xaR2rxHggFLs9wDAGNWt0rmjDo7Xat6
RlrEVqOSan46SnYHE9YO534BzZYFNqFpbYxcyzRnL7jV6jG7hZYtc8l8hjKwt2fM
AG2x45JeY/KY9rOzX8NL8Dr1/f66M0NIzjG0wUeGCTwAsMYDCRbX1Yzw8IrT92U/
4hwvNHFj7EuwmZ3VNRg5cjir4RrZW6JJquIcbu8YplHVVD7C3+93iZRezddL73Mc
99DYI2DPmIwcjUrHBQmyhyI3umHNCbk6Bq5rxYLXLtvGcDpDbFTB6KnlHAziZkvc
NgRlu8/v40PSZGNbcPT9Ow7PtWROBYaWXOfo4K14wIBvYm5Fba9wm1OJIM09uyNm
KwXADh3q
=jKMy
-----END PGP SIGNATURE-----
對訊息進行驗章
簽章完成後,當然就要進行「驗章」功能。
我們以上述的 test.sig
檔案,搭配 test.txt
原始內容為例進行驗證,其使用範例如下:
gpg --verify test.sig test.txt
如果簽章檔本身就包含了訊息內容本身,那麼命令就會長這樣:
gpg --verify test.sig
驗章的時候會輸出以下資訊:
gpg: Signature made Wed May 11 16:05:06 2022 TST
gpg: using RSA key 138711BA41E360645F37E23CC22DCF85C7B99245
gpg: Good signature from "Will Huang <will@example.com>" [ultimate]
你只要看到 Good signature
就代表這是一個受信任的簽章!
當然,如果你不單單只想驗章而已,而是要取出簽章中的原始內容,你可以這樣執行:
gpg -o test.txt --decrypt test.sig
注意:若你將命令寫成 gpg --decrypt test.sig --output test.txt
是無法執行的喔,這裡的 --output
參數一定要寫在 --decrypt
命令的前面。
這裡分享一個可以顯示簽章更完整資訊的命令:
gpg --list-packets -vv --show-session-key test.sig
結果如下:
gpg: armor: BEGIN PGP SIGNATURE
# off=0 ctb=89 tag=2 hlen=3 plen=435
:signature packet: algo 1, keyid 72C7E6D61301F933
version 4, created 1652255448, md5len 0, sigclass 0x00
digest algo 8, begin of digest 86 1c
hashed subpkt 33 len 21 (issuer fpr v4 3DAEA091CA561D2E482A954172C7E6D61301F933)
hashed subpkt 2 len 4 (sig created 2022-05-11)
subpkt 16 len 8 (issuer key ID 72C7E6D61301F933)
data: [3070 bits]
對訊息進行加密
若是牽涉到「加密」與「解密」,就絕對不能忽略「發送端」與「接收端」的身份。你想使用 GPG 對訊息進行加密,就一定要先取得「對方」的 GPG 公開金鑰,並且匯入到你的 GPG Keychain 之中,然後你才能指定將訊息「加密」給「特定人」。
假設你想要傳送給我一個加密檔案,就可以先到 https://github.com/doggy8088.gpg 取得我的公開金鑰 (我發佈到這裡),下載之後,就可以用以下命令匯入:
gpg --import doggy8088.gpg
匯入成功後,你將會看到以下內容:
gpg: key 1F1BD86D70187EC1: "Will Huang <xxxx@xxxx.com>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
你也可以利用 gpg --list-keys
列出目前匯入的所有 Keys
接著,你就可以開始加密檔案給某人了:
gpg --recipient xxxx@xxxx.com --encrypt test.txt
# or
gpg -r xxxx@xxxx.com --encrypt test.txt
這個命令會產生 test.txt.gpg
檔案,該檔案一樣是壓縮過的,不過整個檔案都有加密處理,非常安全。
對訊息進行解密
解密的過程非常簡單,不過你可以試試解開「加密給我」的檔案:
gpg --decrypt test.txt.gpg
你會看到 gpg: decryption failed: No secret key
訊息,因為你並沒有我的「私密金鑰」,即便你是加密的那個人,一樣打不開你指名要給我的檔案!
gpg: encrypted with 2048-bit RSA key, ID 144D30F4B2A611D3, created 2018-04-29
"Will Huang <xxxx@xxxx.com>"
gpg: decryption failed: No secret key
如果在我的電腦,你就會看到以下訊息,而且會產生 test.txt
原始內容:
gpg: encrypted with 2048-bit RSA key, ID 144D30F4B2A611D3, created 2018-04-29
"Will Huang <xxxx@xxxx.com>"
講到這裡,你應該已經學會了「簽章」、「驗章」、「加密」、「解密」等主要功能了! 👍
管理 GPG Keychain (鑰匙圈)
你可以從本機列出目前已有的金鑰資訊,金鑰區分「公開金鑰」與「私密金鑰」兩種。公開金鑰是可以在網路上流傳的版本,用來驗證特定訊息是否由同一個人所簽章過。私密金鑰是你必須安全保存的版本,用來對訊息簽章或加密之用。
-
列出公開金鑰清單
gpg --list-keys
gpg --list-keys --keyid-format SHORT
gpg --list-keys --keyid-format LONG
-
列出私密金鑰清單
gpg --list-secret-keys
gpg --list-secret-keys --keyid-format SHORT
輸出範例如下:
sec rsa3072/6CD3257D 2022-05-11 [SC]
469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
uid [ultimate] Will Huang <will@example.com>
ssb rsa3072/25580607 2022-05-11 [E]
gpg --list-secret-keys --keyid-format LONG
輸出範例如下:
sec rsa3072 2022-05-11 [SC]
469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
uid [ultimate] Will Huang <will@example.com>
ssb rsa3072 2022-05-11 [E]
上述輸出 sec
就是 secret
(私密金鑰) 的意思,而 469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
是完整的金鑰ID,你可以用簡短的金鑰ID替代,也就是 6CD3257D
這段。
匯出 GPG 私鑰
當你想重灌電腦的時候,就需要將你的私鑰備份起來,以下是備份步驟:
gpg --export-secret-keys 6CD3257D > willexample.key
匯出純文字版本的私密金鑰,只要加上 --armor
參數:
gpg --armor --export-secret-keys 6CD3257D > willexample.key
匯出金鑰時會需要你輸入金鑰的密碼。
匯入 GPG 私鑰 (公鑰也會一併匯入)
gpg --import willexample.key
匯入金鑰時也會需要你輸入金鑰的密碼。
匯出 GPG 公鑰
由於 GPG 公鑰本來就是應該要公開的,許多人會將公鑰放在自己的個人網站上,或是直接放在 GitHub 給其他人下載。
匯出公鑰的方式如下:
gpg --export 6CD3257D > willexample.gpg
匯出純文字版本的金鑰,只要加上 --armor
參數:
gpg --armor --export 6CD3257D > willexample.gpg
其實你可以將 GPG 公開金鑰發佈到 GitHub 帳號下,你可以在使用者設定的 SSH and GPG keys 頁面進行新增。以我個人的 GitHub 帳號為例 doggy8088
,其公鑰的所在網址就是 https://github.com/doggy8088.gpg,非常好記! 👍
匯入其他人的 GPG 公鑰
匯入別人的公鑰,可以直接透過以下命令匯入:
gpg --import willexample.gpg
如果要匯入我在 GitHub 的公鑰,則只要輸入以下命令:
curl -s -o doggy8088.gpg https://github.com/doggy8088.gpg
gpg --import doggy8088.gpg
匯入金鑰之後,執行 gpg --list-keys
命令會看到一個 [ unknown]
字樣,這意味著這個金鑰的信任層級為未知。
# gpg --list-keys --keyid-format SHORT
/c/Users/WDAGUtilityAccount/.gnupg/pubring.kbx
----------------------------------------------
pub rsa2048/70187EC1 2018-04-29 [SC]
3B024BEF47B2DED3D163B7521F1BD86D70187EC1
uid [ unknown] Will Huang <xxxx@xxxx.com>
sub rsa2048/B2A611D3 2018-04-29 [E]
pub rsa3072/6CD3257D 2022-05-11 [SC]
469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
uid [ultimate] Will Huang <will@example.com>
sub rsa3072/25580607 2022-05-11 [E]
你可以使用自己的金鑰簽署這份公開金鑰,由你來確認這份公鑰是「可信任的」:
gpg --sign-key 70187EC1
你要手動按個 y
來確認簽署:
pub rsa2048/1F1BD86D70187EC1
created: 2018-04-29 expires: never usage: SC
trust: unknown validity: unknown
sub rsa2048/144D30F4B2A611D3
created: 2018-04-29 expires: never usage: E
[ unknown] (1). Will Huang <xxxx@xxxx.com>
pub rsa2048/1F1BD86D70187EC1
created: 2018-04-29 expires: never usage: SC
trust: unknown validity: unknown
Primary key fingerprint: 3B02 4BEF 47B2 DED3 D163 B752 1F1B D86D 7018 7EC1
Will Huang <xxxx@xxxx.com>
Are you sure that you want to sign this key with your
key "Will Huang <will@example.com>" (9901E05A6CD3257D)
Really sign? (y/N) y
也可以透過 --command-fd 0
來自動化這個過程:
-
Linux/macOS/WSL
echo -e "y\n" | gpg --command-fd 0 --expert --sign-key 70187EC1
-
Windows 命令提示字元
(echo y) | gpg --command-fd 0 --sign-key 70187EC1
-
Windows PowerShell
$(echo y) | gpg --command-fd 0 --sign-key 70187EC1
若在用一次 gpg --list-keys
命令列出所有金鑰,此時你就會看到這把公開金鑰已經是 full
信任等級了!
pub rsa3072 2022-05-11 [SC]
469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
uid [ultimate] Will Huang <will@example.com>
sub rsa3072 2022-05-11 [E]
pub rsa2048 2018-04-29 [SC]
3B024BEF47B2DED3D163B7521F1BD86D70187EC1
uid [ full ] Will Huang <xxxx@xxxx.com>
sub rsa2048 2018-04-29 [E]
若用 gpg --check-signatures
可以列出所有驗證過簽名有效的公開金鑰清單:
pub rsa3072 2022-05-11 [SC]
469B8A7CD0BF30AD3F58AEEB9901E05A6CD3257D
uid [ultimate] Will Huang <will@example.com>
sig!3 9901E05A6CD3257D 2022-05-11 Will Huang <will@example.com>
sub rsa3072 2022-05-11 [E]
sig! 9901E05A6CD3257D 2022-05-11 Will Huang <will@example.com>
pub rsa2048 2018-04-29 [SC]
3B024BEF47B2DED3D163B7521F1BD86D70187EC1
uid [ full ] Will Huang <xxxx@xxxx.com>
sig!3 1F1BD86D70187EC1 2018-04-29 Will Huang <xxxx@xxxx.com>
sig! 9901E05A6CD3257D 2022-05-11 Will Huang <will@example.com>
sub rsa2048 2018-04-29 [E]
sig! 1F1BD86D70187EC1 2018-04-29 Will Huang <xxxx@xxxx.com>
gpg: 5 good signatures
透過金鑰伺服器傳遞公鑰
透過 --send-keys
命令,可以將你的公鑰自動送到 GPG 預設的 金鑰伺服器 (keyserver
)。像我的 Ubuntu 18.04.2 LTS 作業系統,預設就設定了 hkps.pool.sks-keyservers.net
這台當成我的預設金鑰伺服器。而我的 Git for Windows 預設的 keyserver
則是 hkps://keyserver.ubuntu.com
。執行時可以看到以下訊息:
$ gpg --send-keys 6CD3257D
gpg: sending key 9901E05A6CD3257D to hkps://keyserver.ubuntu.com
除此之外,你也可以明確指定金鑰伺服器來上傳,例如 keyserver.ubuntu.com
就相當穩定,速度也較快:
gpg --keyserver keyserver.ubuntu.com --send-keys 6CD3257D
上傳公開金鑰到金鑰伺服器之後,你就可以到 https://keyserver.ubuntu.com/ 直接透過你的 E-mail 信箱即可搜尋到公鑰!
接著你找到另外一台電腦,就可以透過 --recv-key
命令直接匯入你的公鑰,這樣就方便多了:
gpg --keyserver keyserver.ubuntu.com --recv-key 6CD3257D
如果要匯入我的公開金鑰,可以輸入 gpg --keyserver keyserver.ubuntu.com --recv-key 70187EC1
命令!
刪除用不到的金鑰組
如果公鑰私鑰都在同一台電腦,你必須先刪除私鑰,才能刪除相對應的公鑰。也可以直接刪除私鑰就好,公鑰保留。
相關連結