使用 GnuPG (GPG) 非對稱加密限制只有授權人員可閱讀 使用 GnuPG (GPG) 非對稱加密限制只有授權人員可閱讀

Published on Wednesday, March 29, 2023

GnuPG Encryption

在昨天的文章 中,學習到目前在 Linux 環境中是如何對軟體進行簽章的
今天要來學習另一個主要的功能就是『非對稱加密』,跟我們在使用壓縮軟體時對壓縮檔加密的『對稱加密』方式不同 『非對稱加密』需要一組密鑰,一個『公開』的密鑰與一個『私人』的密鑰,在昨天的範例中也有提到相關的例子

作者在進行簽章時需要先產生一組密鑰,會利用作者的私人的密鑰進行加密,之後下載人要導入作者的公鑰對下載的軟體進行驗證,確保下載的檔案是沒有被竄改的
不過在這個流程中是不會對檔案進行加密,也就是說你也可以不管安全性直接執行下載的軟體不進行檢查,這種模式很長用來散佈軟體
今天如果我希望只有我指定的人才能安裝我的軟體,有辦法做到嗎?

那就要利用到 GPG 的非對稱加密,我們可以來進行幾個範例 今天也是使用 play with docker 來進行測試 先建立三台 Instance 每一台都安裝 gnupg 以及產生密鑰

192.168.0.28	node1
192.168.0.27	node2
192.168.0.26	node3

apk add gnupg

gpg --generate-key
------------------------
pub   rsa3072 2023-03-29 [SC] [expires: 2025-03-28]
      A44E732959D72B0D9595C9D0BE437BED0A2ABA19
uid                      node1 <node1@gmail.com>
sub   rsa3072 2023-03-29 [E] [expires: 2025-03-28]

------------------------
pub   rsa3072 2023-03-29 [SC] [expires: 2025-03-28]
      78AA00EAB3652F1EB40B3D114AB94B2F1093CCCE
uid                      node2 <node2@gmail.com>
sub   rsa3072 2023-03-29 [E] [expires: 2025-03-28]

------------------------
pub   rsa3072 2023-03-29 [SC] [expires: 2025-03-28]
      1CD6EC5E3D3618217C881A18BC7EC16175B7072D
uid                      node3 <node3@gmail.com>
sub   rsa3072 2023-03-29 [E] [expires: 2025-03-28]

完成之後我們回到 node1 建立測試資料

mkdir -p gpg && cd $_
vi work-list.txt

1. work A
2. work B
3. work C

我們接下來的目標是加密這個 work-list.txt 並且指定只有 node2@gmail.com 這個使用者才能查看

gpg --encrypt --recipient node2@gmail.com work-list.txt

因為目前 node1 node2 node3 都互相不認識,所以我們須要先將 node2 的公開密鑰匯入給 node1,這樣 node1 才能知道 node2 這個使用者,之後才能加密 如果沒有先在 node1 匯入 node2 的公開密鑰就直接進行加密,會輸出報錯內容提示找不到 node2 的 公開密鑰

[node1] (local) root@192.168.0.28 ~/gpg
$ gpg --encrypt --recipient node2@gmail.com work-list.txt
gpg: error retrieving 'node2@gmail.com' via WKD: No data
gpg: node2@gmail.com: skipped: No data
gpg: work-list.txt: encryption failed: No data

所以我們需要先回到 node2 輸出公開密鑰並且傳送給 node1 這邊輸出的 node2.gpg 為二進制檔案之後使用 scp 複製回 node1 也可以輸入 --armor 參數,輸出成 ASCII 格式就可以直接複製貼上回 node1 上

mkdir -p gpg && cd $_
gpg --output node2.gpg --export node2@gmail.com
#gpg --output node2.asc --armor --export node2@gmail.com

scp /root/gpg/node2.gpg ip172-18-0-102-cgi0hm8sf2q00099eedg@direct.labs.play-with-docker.com:/root/gpg/node2.gpg

回到 node1 會看到剛剛輸出的 node2.gpg

[node1] (local) root@192.168.0.28 ~/gpg
$ ls -l
total 8
-rw-r--r--    1 root     root          1743 Mar 29 10:16 node2.gpg
-rw-r--r--    1 root     root            30 Mar 29 10:02 work-list.txt

接下來使用 --import 參數,匯入 node2.gpg

gpg --import node2.gpg
[node1] (local) root@192.168.0.28 ~/gpg
$ gpg --import node2.gpg
gpg: key 4AB94B2F1093CCCE: public key "node2 <node2@gmail.com>" imported
gpg: Total number processed: 1
gpg:               imported: 1

輸入 gpg -k 檢查目前所有的公開密鑰

[node1] (local) root@192.168.0.28 ~/gpg
$ gpg -k
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2025-03-28
/root/.gnupg/pubring.kbx
------------------------
pub   rsa3072 2023-03-29 [SC] [expires: 2025-03-28]
      A44E732959D72B0D9595C9D0BE437BED0A2ABA19
uid           [ultimate] node1 <node1@gmail.com>
sub   rsa3072 2023-03-29 [E] [expires: 2025-03-28]

pub   rsa3072 2023-03-29 [SC] [expires: 2025-03-28]
      78AA00EAB3652F1EB40B3D114AB94B2F1093CCCE
uid           [ unknown] node2 <node2@gmail.com>
sub   rsa3072 2023-03-29 [E] [expires: 2025-03-28]

再次加密我們的 work-list.txt

[node1] (local) root@192.168.0.28 ~/gpg
$ gpg --encrypt --recipient node2@gmail.com work-list.txt
gpg: A298BCE2539F6EB5: There is no assurance this key belongs to the named user

sub  rsa3072/A298BCE2539F6EB5 2023-03-29 node2 <node2@gmail.com>
 Primary key fingerprint: 78AA 00EA B365 2F1E B40B  3D11 4AB9 4B2F 1093 CCCE
      Subkey fingerprint: 072E EF81 F0D2 9A9D B97C  2D4A A298 BCE2 539F 6EB5

It is NOT certain that the key belongs to the person named
in the user ID.  If you *really* know what you are doing,
you may answer the next question with yes.

Use this key anyway? (y/N) y

就能成功看到 work-list.txt.gpg 代表已經加密成功了,並且只有 node2 才能解密

[node1] (local) root@192.168.0.28 ~/gpg
$ ls -l
total 12
-rw-r--r--    1 root     root          1743 Mar 29 10:16 node2.gpg
-rw-r--r--    1 root     root            30 Mar 29 10:02 work-list.txt
-rw-r--r--    1 root     root           490 Mar 29 11:49 work-list.txt.gpg

我們將 work-list.txt.gpg 複製到 node2 上

scp /root/gpg/work-list.txt.gpg ip172-18-0-3-cgi0hm8sf2q00099eedg@direct.labs.play-with-docker.com:/root/gpg/work-list.txt.gpg

並且嘗試對檔案進行解密,解密中需要輸入 node2 的密碼

gpg --output work-list.txt --decrypt work-list.txt.gpg

可以成功將原始檔案還原

[node2] (local) root@192.168.0.27 ~/gpg
$ ls -l
total 16
-rw-r--r--    1 root     root          2440 Mar 29 10:18 node2.asc
-rw-r--r--    1 root     root          1743 Mar 29 10:14 node2.gpg
-rw-r--r--    1 root     root            30 Mar 29 11:55 work-list.txt
-rw-r--r--    1 root     root           490 Mar 29 11:52 work-list.txt.gpg

[node2] (local) root@192.168.0.27 ~/gpg
$ cat work-list.txt
1. work A
2. work B
3. work C

接下來回到 node1 將 work-list.txt.gpg 複製到 node3 上

ssh ip172-18-0-103-cgi0hm8sf2q00099eedg@direct.labs.play-with-docker.com "mkdir -p /root/gpg/" &&
    scp /root/gpg/work-list.txt.gpg ip172-18-0-103-cgi0hm8sf2q00099eedg@direct.labs.play-with-docker.com:/root/gpg/work-list.txt.gpg

複製成功後來到 node3 上並且嘗試解密,會輸出這個檔案是專門為 node2 加密的,因為非對稱加密的特性,我們使用 node2 的公開密鑰加密,能解開檔案的只有擁有 node2 私人密鑰的人才有能力進行解密

[node3] (local) root@192.168.0.26 ~/gpg
$ gpg --output work-list.txt --decrypt work-list.txt.gpg
gpg: encrypted with 3072-bit RSA key, ID A298BCE2539F6EB5, created 2023-03-29
      "node2 <node2@gmail.com>"
gpg: decryption failed: No secret key

就算是當初進行加密的機器 node1 也沒有能力進行解密

[node1] (local) root@192.168.0.28 ~/gpg
$ gpg --output work-list.txt --decrypt work-list.txt.gpg
gpg: encrypted with 3072-bit RSA key, ID A298BCE2539F6EB5, created 2023-03-29
      "node2 <node2@gmail.com>"
gpg: decryption failed: No secret key

Summary

今天學習了如何使用 gpg 的非對稱加密,來安全的將檔案傳送給我們指定的使用者,就算檔案中途被其他人取得也沒有辦法知道檔案的內容
因為只有擁有私人密鑰的人才能夠進行解密,這樣可以達成非常高的安全性並且可以利用在 email 這種單人對單人的傳輸,就算內容被攔截也沒有辦法還原成原始內容