2

GPG 筆記 - 產生 ECC 金鑰及加解密檔案

 1 year ago
source link: https://blog.darkthread.net/blog/gpg-gen-key-n-encrypt/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

GPG 筆記 - 產生 ECC 金鑰及加解密檔案

2023-07-30 11:36 PM 0 991

如果你對 GPG(GnuPG) 跟 ECC 金鑰沒什麼概念,這裡先提供一些背景知識。

GPG (The GNU Privacy Guard,又稱 GnuPG),是一套實作 OpenPGP 標準規開源軟體,使用 Windows 的同學或許較少接觸,但它成為 Linux / macOS 內建工具很久了,Git 也支援用它為 Git Commit 加上數位簽章,而 Github 在你開帳號時已幫你建好一把 GPG 金鑰,也允許你上傳自己的 GPG 金鑰用在自己的開源專案。關於 GPG 的使用簡介,推薦保哥這篇:如何使用 GPG (GnuPG) 對 Git Commit 與 Tag 進行簽章

前陣子玩 OpenSSH 免密碼登入時學到新知識:在非對稱金鑰(一次兩把金鑰成對使用,分為公私鑰,公鑰可公開、私鑰要保密)密碼學領域,RSA 早非主流,重度依賴數位簽章的加密貨幣都已改用 ECC (延伸閱讀:數位簽章知識補充包 - ECC 橢圓曲線密碼學、Ed25519、Curve 25519),而最新版 GPG 在建立金鑰時,預設選項也已是 ECC 而非 RSA。因此,除非有相容舊系統需求,現在要做數位簽章或高強度加密,都建議使用 Ed25519、Curve 25519 等標準。

這篇會來簡單示範如何在 Windows 用 GPG 產生 Curve 25519/Ed25519 金鑰,並用它完成加解密。

建立 ECC 金鑰

假設我們是第一次在 Windows 上使用 GPG,要建立人生第一把 GPG 金鑰。

  1. 首先,建議安裝 Gpg4win,Git for Windows 也有內建 gpg,但 Gpg4win 跟 Windows 整合性較好,如果你想用 GPG 金鑰登入 SSH,用 Gpg4win + Win32 OpenSSH 最新版本問題較少。
    要安裝可至網站下載安裝程式或使用 Chocolatey choco install -y gpg4win,我推薦後者。延伸閱讀:指令式軟體安裝服務比較:Chocolatey、Scoop 與 winget
  2. 安裝好可用 gpg --version 看一下版本跟另一個重要訊息 - Home。Gpg4win 的 Home 在 %UserProfile%\AppData\Roaming\gnupg,Git 附的 gpg 則在 %UserProfile%\.gnupg,這是放設定檔跟保存金鑰的地方,將來可能會用到。
  3. 現在來產生第一把加解密跟簽署用的 ECC 金鑰。
    輸入 gpg --full-generate-key,開始的三個選項都用預設值即可,選 9) ECC (sign and encrypt) / 1) Curve 25519 / 0 = key does not expire:
    Fig2_638263282146044331.png
  4. 再來輸入 Real name (姓名)、Email (可忽略)、Comment (備註說明,可忽略),gpg 會提示要輸入一組密碼,未來匯出匯入私鑰時會用到。密碼建議至少 8 碼,太短會提示強度不足,但堅持的話還是可以用。
    Fig3_638263282148132559.png
  5. 只需要幾秒鐘金鑰就產生完成了,gpg 會顯示金鑰資訊,pub 是 Ed25519 公鑰,[SC] 表示它的用途,S 代表 Signing 簽章,C 代表可以建立憑證 Certification;另外有支加密用的 sub 子金鑰 (Cv25519),用途為 [E] Encryption 加密。另外,如果要用這組金鑰進行 SSH 認證,需要再手動建一個子金鑰 (其用途為 [A] Authentication),這部分未來有機會再介紹。
    This is a list of letters indicating the allowed usage for a key (E=encryption, S=signing, C=certification, A=authentication). 參考
    pub 金鑰下方有串 ID 數字,未來要管理金鑰時可輸入最後八碼作為識別:
    Fig4_638263282150216383.png

金鑰建立完成後,若別人要加密資料給你,你必須將公鑰傳送給他,請對方用你的公鑰加密資料。公鑰可以對全世界公開,故用任何方式傳送都無所謂,寄 Email、用 USB 行動碟傳、丟到雲端磁碟機讓對方抓,印出來貼在巷口電線桿上,都行。另外,你也可以選擇將公鑰上傳到公共伺服器,例如:keys.openpgp.org 、pgp.mit.edu... 參考 讓想傳密件給你的人都能在伺服器下載你的公鑰。

私鑰則恰恰相反,要用最高規格藏好不可外流,一旦外流好比遺失提款卡,撿到的人又剛好知道你的密碼,就能去 ATM 領錢(所以前面第 4 步驟的密碼要長一點複雜一點);私鑰檔案不比 ATM 有錯三次密碼的保護,駭客可以 Try 到爽,這也是為什麼實體金鑰又比私鑰檔案安全,私鑰可以被鎖在硬體模組永遠無法匯出或複製,另有 PIN 碼保護加輸錯次數限制,錯三次就鎖住停用,若連解鎖 PIN 碼都錯則自動將金鑰刪除,寧可自盡也不要被壞人利用。

gpg --export <userName> > pub-key.key 可匯出二進位檔,加上 -a 或 --armor 參數則可輸出類似 PEM 格式轉為 Base64 編碼的文字檔:

Fig5_638263282152325877.png

-a 輸出成文字格式應用比較方便,可複製貼上,當成 Email 本文、網頁 TextArea 輸入內容傳送。

到目前為止,公私鑰都存在你的電腦磁碟機上,只要是資料都應該要備份。公鑰通常會到處發送上傳,副本很多,不愁失傳;但私鑰目前只有一份,萬一檔案壞了、硬碟掛掉,加密的東西永遠都解不開,那可不行。所以產生完公私鑰後很重要的一件事是 - 匯出私鑰,並將其備份在安全的地方保管(還有金鑰密碼不要忘了),最好是離線媒體(但要小心行動碟快閃記憶體放久資料消失),平時無法從遠端存取,如此較安全。還有一種做法是輸出成純文字,列印紙本收藏好,多一種保存方式,多一份保險。

指令與匯出公鑰相同,把 --export 改成 --export-secret-key 即可。另外匯出私鑰時需要輸入密碼:

Fig6_638263282154194544.png

把場景拉到通訊對象。我們切換到另一個使用者 demo,想設他想要傳只有 Jeffrey 能解密的資料給你,在電腦上已裝好 Gpg4win 但沒有建立任何金鑰(若沒有要簽章或解密,不需建立金鑰),使用 gpg -kgpg --list-key 可檢視已知的金鑰,首次執行會先建立 trustdb.gpg 資料檔來保存金鑰。第二次執行沒傳回任何結果,代表目前裡面沒有半把金鑰。

使用指令 gpg --import file-name-of-pub-key 匯入前面用 gpg --export 匯出的公鑰檔(二進位或純文字檔案均可),之後再使用 gpg -k 檢查,可看到匯入 Jeffrey 金鑰的資訊:

Fig7_638263282156074732.png

接著,準備一個內容為 TOP-SECRET 的文字檔 secret.txt,使用 gpg -e -a -r Jeffrey secret.txt 指定用 Jeffrey 的公鑰加密,-a 等於 --armor 代表使用文字檔格式,gpg 依循 POSIX 參數慣例,故 -e -a -r Jeffrey 也可寫成 -ear Jeffrey。(延伸閱讀:POSIX 參數慣例的冷知識)

由於我們未將 Jeffrey 的公鑰標註為可信任,加密時 gpg 會彈出確認,詢問你是否確認要使用這把金鑰?若確認,gpg 便會用該公鑰加密檔案,由於加了 -a 參數,加密結果為 -----BEGIN PGP MESSAGE----------END PGP MESSAGE----- 包夾的一段 Base64 編碼內容:

Fig8_638263282158052480.png

要避免公鑰信任提示有兩種方法,一種是加密時加上 --trust-model always 參數;另一種是更改公鑰的信任等級。

若確認金鑰檔的確為對方持有,可在資料庫將其標註為可信任或簽署金鑰,未來加密或檢驗簽章時會直接使用,不再詢問確認。方法為使用 gpg --edit-key Jeffreygpg --edit-key <KEY-ID 最後八碼> 編輯金鑰設定,使用指令 trust 註記信任程度:

Fig9_638263282160111925.png

信任程度有以下選擇,對映到的金鑰持有者的知識水平(笑),None 表示金鑰所有人可能會胡亂簽章(不可信賴)、Marginal 表示知道數位簽章原理,簽署前會仔細確認,Full 則表示對方熟悉金鑰簽章,可以完全信任,Ultimately 則是徹底信任,通常只用在自己的金鑰。參考

  1. I don't know or won't say
  2. I do NOT trust
  3. I trust marginally
  4. I trust fully
  5. I trust ultimately

官方文章對不同信任等級的解釋有點抽象,而其主要影響在於金鑰簽署效力,例如:設成 Full 的金鑰可以用來簽署其他人的公鑰保證其有效性、Marginal 金鑰則需要三個人簽署才具有 Full 金鑰的簽署效力(這個機制太複雜了,不建議使用)。參考 而在加密應用,公鑰要設成 Ultimately 才可省略確認。

BUT! 設定 Ultimately 這招在 Linux 版 gpg 有效,對 Gpg4win 無效,必須透過簽署讓公鑰被信任。參考

最簡單的方法是加密端先建立自己的金鑰對,用自己的私鑰簽署對方公鑰使其被信任。

FigA_638263282162125578.png

簽署完該公鑰的信任等級會變成 Full,加密時便不會再出現確認提示。

FigB_638263282164052190.png

解密步驗相對簡單,密文已包含金鑰資料,使用 gpg -d <file_name> 會自動在金鑰資料庫找到對映的私鑰,輸入密碼:

FigB_638263282164052190.png

得到解密結果。

FigC_638263282165950707.png

若為圖檔、文件,可使用 Pipeline 導向存檔或使用 -o 參數指定輸出檔案:

gpg -d sample.jpg.asc > sample.jpg
gpg -d -o sample.jpg sample.jpg.asc

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK