- APT-KEY 金鑰管理 □ 文/dbtsai
讀者或許會好奇,Ubuntu 怎麼能保證全世界那們多台 mirror 站提供的套件不是經過有心的駭客入侵更改的,或者駭客自己架一台 mirror 站,再用 DNS 挾持的方式,把您引導到他自己架的套件庫上,並在您系統更新時順便植入後門。
讀者或許會好奇,Ubuntu 怎麼能保證全世界那們多台 mirror 站提供的套件不是經過有心的駭客入侵更改的,或者駭客自己架一台 mirror 站,再用 DNS 挾持的方式,把您引導到他自己架的套件庫上,並在您系統更新時順便植入後門。
在 Debian 和 Ubuntu 採用簽章的方式來解決這個問題。簽章可以證明這些套件檔是由 Ubuntu 官方所出,而沒有經過別人所篡改,並且這個簽章是跟著套件一起跑,不管跑到哪一個 mirror 站,都無法改變的。如果這個套件檔被有心人士修改加入後門,那麼這個簽章將會失效,此時 APT 系統就會判別出這個套件經過人家改動,而提出警告。
所謂的簽章,是透過金鑰的功能來達成。完整的金鑰有兩隻鑰匙,一隻是私鑰 (Private Key),另外一隻是公鑰 (Public key),而公鑰和私鑰是一對的,並且是一起產生的。金鑰加密的基礎是,當我們用私鑰對一段訊息加密後,我們只能用公鑰把它解開,反之如此。因此其實公鑰和私鑰其實地位是一樣的,就看您要把哪一把當成公鑰,哪一把當成私鑰。這種加密方式就是所謂的非對稱式密碼系統。當然讀者或許會覺得奇怪,理論上我們知道一把公鑰後,應該是可以算出一把私鑰和這把公鑰吻合,這樣不就破解了嘛?的確如此,不過以一把鑰匙算出成對的另外一把鑰匙是幾乎不可能在有限的時間內計算出來的,以現在的電腦能力,破解一把高位元的鑰匙,都要數十年的時間,所以這種加密的安全性主要是依賴於從公鑰推出私鑰的計算所需的時間。但沒有人保證明天的電腦科技不會突飛猛進,造成可以在合理的時間內破解金鑰,但目前這種加密方式仍然是很可靠的。
我們如何透過這種系統來進行秘密通訊呢?舉例 A 和 B 要進行秘密通訊,而 A 和 B 的公鑰都已經公佈出來,彼此都知道了。此時 A 可以用 B 的公鑰把要傳給 B 的訊息加密,如此這段訊息只有用 B 的私鑰才能解開,因而達到秘密通訊的要求。同理,B要傳秘密訊息給 A,就用 A 的公鑰加密,如此就只有 A 能解開這段文字。這也是為什們私鑰很重要了,這種加密方式安全度就看私鑰有沒有保管好。總之,公鑰可以公佈出去,給越多人知道也沒關係,但私鑰就要自己好好保管,絕不能外洩。
在套件管理系統中,採用的簽章系統加密的想法和前面秘密通訊剛好反向。若要確定檔案是從官方來的,此時官方組織會用私鑰加密,這時只有公鑰能夠解密。當 Ubuntu 用私鑰加密一段文字後,使用者可以用 Ubuntu 的公鑰去把它解開來。但若是駭客沒有 Ubuntu 的私鑰,隨便用個鑰匙加密,那麼我們用 Ubuntu 的公鑰去解密,會出現失敗。因此只要我們的公鑰是正確的,我們就可以判斷檔案或文字是否是由 Ubuntu 官方出來的。
問題是透過私鑰加密的檔案會變大,且隨著檔案大小越大,用公鑰解密的時間越來越長,所以把所有套件檔加密是不切實際的。這裡有個變通的方式,是讓所有的人不管有沒有公鑰,都可以知道檔案內容,也就是現在套件檔不加密,只要有辦法確定是官方的就好了。這就是所謂的數位簽章系統,可以保證資料是您所撰寫,類似於我們簽名,雖然內容大家都看的到,但是可以用筆跡來認出是誰簽名的。方法是我們對於要簽章的檔案作單向 hash,例如用 MD5 hash,然後把 hash 後的值用私鑰加密。而驗證的人只要用公鑰確定那段被加密的 MD5 hash 是否是由私鑰產生的,並且可以把它解密後在對文件做一次 MD5 hash,如果兩個 hash 的值都一樣,那代表是本人寫的,沒有被篡改過。
實際上 Ubuntu 的套件管理系統是用 MD5 和簽章系統來配合做驗證。所有的套件檔都會產生 MD5 hash,這些 MD5 碼可以檢查套件是否完整,是否被改過。當套件被修改過而產生一樣的 MD5 碼是幾乎不可能的,所以我們可以用此值來驗證套件的完整性。現在的問題是如何安全傳遞這些 MD5 hash 值,方法就是簽章系統了。在 APT 系統中,當我們做 apt-get update 時,會向套件庫取得兩個檔案,Release 和 Release.gpg。在 Release 裡面包含了套件庫所有 deb 套件的 MD5 hash,而保障 Release 是沒被篡改過的方法是透過 Release.gpg,也就是簽章。Release.gpg 包含了官方對 Release 做單向 hash 後再用私鑰加密的資訊。因此我們可以用公鑰來驗證 Release.gpg 是否由私鑰所加密的,並用解出來的資訊再對 Release 驗證是否被篡給過。
這些內容在資工系密碼學都要學一學期,所以如果以上太艱深的話,沒關係。重點是只要知道它能保障您下載的套件檔是沒有被篡改過的就行了。以下我們要說明實務上要如何管理 APT 系統的公鑰。
我們先列出 APT 系統目前有的公鑰看看,當然 Ubuntu 套件庫所用的公鑰在您安裝好系統後,就已經裝好啦! 指令:
-
sudo apt-key list # 列出 APT 系統所使用的公鑰
範例:
-
dbtsai@ubuntu:~$ sudo apt-key list /etc/apt/trusted.gpg -------------------- pub 1024D/437D05B5 2004-09-12 # 1024D 此欄代表著金鑰擁有者 ID,437D05B5 此欄是金鑰指紋 uid Ubuntu Archive Automatic Signing Key <[email protected]> sub 2048g/79164387 2004-09-12 pub 1024D/FBB75451 2004-12-30 uid Ubuntu CD Image Automatic Signing Key <[email protected]> dbtsai@ubuntu:~$
您會發現 APT 系統上目前有兩把公鑰,一把是給光碟用的,另外一把是給套件庫所使用的。而我們好好的幹嘛還要裝新的公鑰呢?常常金鑰都會設幾年的保存期限,避免有心人用超級電腦從公鑰算出私鑰。這種金鑰過期的情形在 Debian 就發生過,幾年前 Debian 就換過金鑰導致很多人套件管理系統無法更新。或者我們常常加入個人的套件庫,他們當然沒有 Ubuntu 的私鑰(這可是 Ubuntu 最保密的事情呢!),所以系統上的公鑰就無法驗證這些套件庫,所以我們就得要手動把相對應的公鑰裝上去。
例如筆者很喜歡在我的 Ubuntu 上加上 Debian unstable 和 experiment 的原始碼套件源,這樣我可以透過套件管理系統來自動編譯最新的套件。當然在 Ubuntu 裡面沒有 Debian 的公鑰,如以下範例,會產生錯誤訊息。 範例:
-
dbtsai@ubuntu:~$ cat /etc/apt/sources.list deb-src http://ftp.debian.org.tw/debian experimental main deb-src http://ftp.debian.org.tw/debian unstable main deb http://apt.ubuntu.org.tw/ubuntu/ dapper main restricted deb-src http://apt.ubuntu.org.tw/ubuntu/ dapper main multiverse dbtsai@ubuntu:~$dbtsai@ubuntu:~$ sudo apt-get update 下載:2 http://ftp.debian.org.tw unstable Release.gpg [189B] 下載:9 http://ftp.debian.org.tw unstable Release [38.3kB] 中間略 W: GPG error: http://ftp.debian.org.tw unstable Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 010908312D230C5F W: 用『apt-get -f install』指令或許能修正這些問題。 dbtsai@ubuntu:~$
此時系統抱怨找不到公鑰 (NO_PUBKEY 010908312D230C5F)。或許讀者會覺得奇怪,公鑰那們短不是一下子就會被破解了嘛!其實那不是公鑰,而是金鑰指紋的最後 16 碼。一般高位元的金鑰,公鑰大小會有 2K以上,這樣若要給別人公鑰除非是用磁片傳,不然無法很容易傳遞。想想看 2K 可以紀錄一千多個中文字耶!總不能唸給別人聽吧!所以有人就想到一個交換公鑰的方式,利用 key server 來傳遞。我們先對金鑰取特徵值,得到一組金鑰指紋,有40碼,每一碼都是從 0 到 F,以十六進位表示。然後我們可以把公鑰上傳到 key server,其他人只要憑金鑰指紋就可以下載,這樣就解決了煩人的公鑰交換問題。
例如筆者的金鑰是 DSA + Elgamal 4096bits,而我的鑰匙資訊如下: 筆者的金鑰:
-
pub 1024D/91AFDF6C 2006-08-02 金鑰指紋 = A612 E53D DE36 5627 4F60 665D 2451 ACB6 91AF DF6C uid Dung-Bang Tsai (dbtsai) <[email protected]> sub 4096g/A1F68A40 2006-08-02
筆者產生了金鑰後,其中的資訊 1024D/91AFDF6C 是我們最常用的。前面的 1024D 是從筆者的名子和 E-Mail 算出來,也就是 User ID。後面的 91AFDF6C 是金鑰指紋後八碼。整個組合起來就是您的金鑰 ID。
如果公鑰已經上傳到 key server 上,我們可以透過金鑰指紋後八碼下載到該金鑰的公鑰。例如讀者可以透過以下指令來下載筆者的公鑰: 指令:
-
gpg --keyserver hkp://wwwkeys.eu.pgp.net --recv-keys <金鑰指紋> # 伺服器可以選擇其他的,這些伺服器都會互相同步。 # 所以 eu 可以換成 us cz de 等。 # 而金鑰指紋最少要8碼,或 16 碼,也可以完整的用40碼來下載公鑰。
範例:
-
dbtsai@ubuntu:~$ gpg --keyserver hkp://wwwkeys.eu.pgp.net --recv-keys 91AFDF6C gpg: 正在請求金鑰 91AFDF6C 自 hkp 伺服器 wwwkeys.eu.pgp.net gpg: 金鑰 91AFDF6C: 公鑰 "Dung-Bang Tsai (dbtsai) <[email protected]>" 已被匯入gpg: 總共被處理的數量: 1 gpg: 已匯入: 1 dbtsai@ubuntu:~$ gpg --list-key /home/dbtsai/.gnupg/pubring.gpg ------------------------------- pub 1024D/91AFDF6C 2006-08-02 uid Dung-Bang Tsai (dbtsai) <[email protected]> sub 4096g/A1F68A40 2006-08-02 dbtsai@ubuntu:~$
回到主題,我們先前談及要下載 Debian 套件庫的公鑰,根據錯誤訊息 NO_PUBKEY 010908312D230C5F,後面那一串就是金鑰指紋。我們可以貼上最後 8 碼,或者 16 碼來下載。
(備註: 通常有在使用金鑰的人都會上傳他的公鑰到伺服器上,若真的沒有上傳的話,就必須和該套件庫的維護者索取。 )
取得 Debian 套件庫公鑰:
-
dbtsai@ubuntu:~$ gpg --keyserver hkp://wwwkeys.eu.pgp.net --recv-keys 010908312D230C5F dbtsai@ubuntu:~$ dbtsai@ubuntu:~$ gpg --list-key /home/dbtsai/.gnupg/pubring.gpg ------------------------------- pub 1024D/2D230C5F 2006-01-03 [過期: 2007-02-07] uid Debian Archive Automatic Signing Key (2006) <[email protected]> dbtsai@ubuntu:~$
由於 APT 系統上所使用的公鑰列表和 gpg 系統的公鑰列表是分別獨立的,所以要把 gpg 的公鑰匯出到 APT 系統。如以下匯出 Debian 公鑰的範例: 指令:
-
gpg --armor --export <金鑰指紋> | sudo apt-key add - # 匯出公鑰到 APT
將剛剛下載的 Debian 公鑰匯入 APT 系統:
-
dbtsai@ubuntu:~$ gpg --armor --export 010908312D230C5F | sudo apt-key add - gpg: 沒有找到任何徹底信任的金鑰 OK dbtsai@ubuntu:~$ sudo apt-key list /etc/apt/trusted.gpg -------------------- pub 1024D/437D05B5 2004-09-12 uid Ubuntu Archive Automatic Signing Key <[email protected]>sub 2048g/79164387 2004-09-12 pub 1024D/FBB75451 2004-12-30 uid Ubuntu CD Image Automatic Signing Key <[email protected]> pub 1024D/2D230C5F 2006-01-03 [過期: 2007-02-07] uid Debian Archive Automatic Signing Key (2006) <[email protected]> dbtsai@ubuntu:~$
若是在伺服器上找不到他的公鑰,讀者可以寫信去要,他會給您他的公鑰,大致上長的像以下範例一樣: 公鑰範例:
-
-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.2.2 (GNU/Linux) mQGiBEO6XBMRBACFyOjxs17kkn0dnzRlMDHFZwcLR3A0xACvC97jbmSvuiH2J1Ku R1JkFqCNGv3yzvtjfLMRrNfmIgitOOaPmjK4erQoXM2cyrHlsk/OXLM2aGcR8PGE 略 -----END PGP PUBLIC KEY BLOCK-----
讀者把它存成文字檔 debian.asc 以後,可以透過以下指令匯入: 指令:
-
sudo apt-key add debian.asc
若是讀者要刪除公鑰,可以透過以下指令: 指令:
-
sudo apt-key del <金鑰指紋>
當然金鑰的使用不只在這裡,只要是有關於安全性的部份,都常常見到它的縱影,往後筆者會在各種不同的應用領域再次介紹到,不過原理大致就如本節所敘述的。
shrink this item