從事安全(解決方案)工作已經二十多年了的前系統工程師。
我作為新人系統工程師在SIer開始工作的時候,
公司提供的電腦上並沒有安裝防病毒軟體。
(或許你會想這不可能,但那時候的安全意識就是這樣)
現在考慮到安全對策已成為經營課題之一,
我感受到,長時間的工作經歷,讓我意識到了許多事情。
(那時候的想法是「安全?那是什麼?」之類的…)
那麼,這次我們來聊聊安全的基礎之一「公開金鑰加密」。
作為一般加密機制而著名的有兩種。「對稱加密」與「非對稱加密」。
在介紹非對稱加密之前,先來解釋對稱加密。
對稱加密是指加密和解密使用相同的金鑰(因為使用相同的金鑰,所以稱為對稱加密)。
我們用簡單的圖示來說明。

這次的主角是愛麗絲與鮑勃。
左邊的愛麗絲用對稱金鑰加密一條文本消息,右邊的鮑勃則用(相同的)對稱金鑰對接收到的加密消息進行解密。
如果沒有對稱金鑰,就會出現以下狀況。
・愛麗絲無法加密文本消息
・鮑勃無法解密加密消息
我們來試試使用openssl進行加密和解密。
環境隨便,但我使用的是AlmaLinux。
$ cat /etc/almalinux-release
AlmaLinux release 9.6 (Sage Margay)
首先確認openssl的版本。
$ openssl version
OpenSSL 3.2.2 4 Jun 2024 (Library: OpenSSL 3.2.2 4 Jun 2024)
接下來進行準備。
這次我們將使用AES-256-CTR進行測試。
(沒有特別的理由,僅因為這是我能在此環境中測試的加密方式)
接下來是愛麗絲的作業,生成加密金鑰(對稱金鑰)。
$ openssl rand 32 > symmetric.key
生成IV。
※IV…Initialization Vector(初始向量)。
$ openssl rand 16 > iv.bin
生成文本消息。
$ echo "My name is Alice." > plain.txt
$ cat plain.txt
My name is Alice.
現在,將這條文本消息進行加密。
文本消息(plain.txt)將被加密成(ciphertext.bin)。
KEYHEX=$(xxd -p -c 256 symmetric.key | tr -d '\n')
IVHEX=$(xxd -p -c 256 iv.bin | tr -d '\n')
openssl enc -aes-256-ctr -nosalt \
-K "$KEYHEX" -iv "$IVHEX" \
-in plain.txt -out ciphertext.bin
$ cat ciphertext.bin
��,7��P��K�k6�+�
加密的消息是二進制數據,因此顯示為亂碼。
(這與主題無關)我們來將其轉換為更易讀的文字。
$ xxd ciphertext.bin
00000000: 0b81 842c 37f2 b650 acc5 4baf 156b 36f5 ...,7..P..K..k6.
00000010: 2be3 +.
到目前為止是愛麗絲的作業。
(加密的消息和對稱金鑰需要以某種方式發送給鮑勃)
接下來是鮑勃的作業。
他將解密這條加密消息。
KEYHEX=$(xxd -p -c 256 symmetric.key | tr -d '\n')
IVHEX=$(xxd -p -c 256 iv.bin | tr -d '\n')
openssl enc -d -aes-256-ctr -nosalt \
-K "$KEYHEX" -iv "$IVHEX" \
-in ciphertext.bin -out decrypted.txt
$ ls decrypted.txt
decrypted.txt
$ cat decrypted.txt
My name is Alice.
恢復成功,看來一切正常。
對了,對稱加密有一個挑戰。
那是什麼呢?
(這個理由正是連結到非對稱加密的根本原因)
那就是「金鑰的傳遞(密鑰配送)」問題。
在對稱加密中,如果沒有金鑰,就無法進行加密和解密。因此,必須以某種方式和對方共享金鑰。
那麼,如何安全地傳遞金鑰呢?
直接將其作為郵件附加檔,這樣做是危險的對吧?
那麼,是否要「加密後再附加」呢??
那麼,為了加密和解密,需要的金鑰又如何共享呢???
這樣一來,似乎就進入了一個迷宮…
Ohhh,真是麻煩…
以前的人想到了這個問題。認為需要一種新的加密方式。
那就是非對稱加密。
(加密有其歷史)
非對稱加密是指加密和解密使用不同的金鑰。
我們用簡單的圖示來說明。

同樣是愛麗絲與鮑勃。
左邊的愛麗絲用公開金鑰對文本消息進行加密,右邊的鮑勃使用私有金鑰解密接收到的加密消息。
這裡的重點是,所使用的金鑰在加密和解密時是不同的。
(加密使用公開金鑰,解密使用私有金鑰)
這種非對稱加密,解決了剛才提到的對稱加密的挑戰。
怎麼說呢,這個「公開金鑰」具有加密的功能,但不具解密的功能。因此,無需擔心它被偷取而不必安全保護。
因此,無需為金鑰的傳遞(密鑰配送)而煩惱(不必擔心如何安全地配送)。
同樣的,我們也試試使用openssl進行非對稱加密和解密。
這次我們使用RSA進行測試(為了進行加密與解密)。
接下來是鮑勃的作業,首先生成私有金鑰。
$ openssl genpkey -algorithm RSA -out rsa_private.pem -pkeyopt rsa_keygen_bits:2048
接著生成公開金鑰。
$ openssl pkey -in rsa_private.pem -pubout -out rsa_public.pem
以上是鮑勃的作業。
(公開金鑰需要以某種方式傳送給愛麗絲)
接下來是愛麗絲的作業。
生成文本消息。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
將該消息進行加密。
$ openssl pkeyutl -encrypt -pubin -inkey rsa_public.pem -in rsa_plain.txt -out rsa_encrypted.bin
(將加密的消息用cat查看會讓終端出現亂碼,所以這次我們跳過)
不過,我們可以將其轉換為易讀的文字。
$ openssl base64 -in rsa_encrypted.bin
d6Hv3nd/3We1Z/9kMwqmhckIUdIUo06TVlLaclPVWhCH8BGtko7cg+EFB6Fx+qT/
hgATgLUlqJvblw65fusOwc3DJFbGlTN7mvuxYBPN2XO8UHYJ5W9av+iwXvMGFJfm
f94HYNl3JGmR5ouGwPKBd+M2zmuf4LiBDFfPzYmdvY1llx6XZCRrm6D62qXROhsQ
lavvPQkGZT2w+k4Y2Enc/jAccldnR6aQcEeSLKNUqw7LSmnjOyTuAjIBgy+yLwWn
nKkvyZria+l9G+KeR0o9n6SLSSOu1d4CWaPAxiRnIXtzOA0ukacZ8vl+LuvAtxOq
5B1rX8xbOcM+SaFlG0HVbg==
到目前為止是愛麗絲的作業。
(加密的消息需要以某種方式傳送給鮑勃)
接下來是鮑勃的作業。
他將解密這條加密消息。
$ openssl pkeyutl -decrypt -inkey rsa_private.pem -in rsa_encrypted.bin -out rsa_decrypted.txt
檢查解密的消息。
$ cat rsa_decrypted.txt
My name is Alice.
成功解密,太好了。
至此,我們已經說明了對稱加密和非對稱加密。
非對稱加密的特性是
但是,其實非對稱加密還有其他用途。
其實,非對稱加密有三種面向。
分別是:
非對稱加密的第一個面向是「加密」。也可以稱為「保密性」。
顧名思義,就是用來進行「加密」的方式,
正如先前所說的「使用公開金鑰加密,使用私有金鑰解密」。
一般來說,大概大家都認為這是最知名的「加密」方式。
(但實際上,使用非對稱加密進行「加密」的案例逐漸減少,特別是系統工程師應該要內心記住這一點)
非對稱加密的第二個面向是「簽名」。
後面會用圖示來說明。
非對稱加密的第三個面向是「鍵共識(密鑰共享)」。
這是一種稍有不同的使用方式。
「加密」與「簽名」中,一方持有私有金鑰,另一方持有公開金鑰。
但在「鍵共識(密鑰共享)」中,雙方都持有私有金鑰和公開金鑰。
而這樣的狀況是雙方共同擁有相同的對稱金鑰(共享)的機制!
接下來我們會用圖示來進一步解釋。
我們用簡單的圖示來說明非對稱加密的簽名。
(雖然這部分稍微複雜一些)

還是那句話,這次的主角是愛麗絲與鮑勃。
左邊的愛麗絲根據文本消息生成簽名。
她不是直接對消息簽名,而是將消息先哈希化,再用私有金鑰對該哈希值進行簽名。
右邊的鮑勃獲取消息和簽名,並根據公開金鑰進行簽名驗證。如果簽名正確則確認無誤,若簽名錯誤則被視為無效。
同樣,我們來使用openssl進行簽名與驗證的實驗。
我們將使用RSA進行測試(RSA不僅可以用於加密和解密,還可以用於簽名與簽名驗證)。
這是愛麗絲的作業。首先生成私有金鑰。
$ openssl genpkey -algorithm RSA -out rsa_private.pem -pkeyopt rsa_keygen_bits:2048
接著生成公開金鑰。
$ openssl pkey -in rsa_private.pem -pubout -out rsa_public.pem
生成文本消息。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
將該消息進行哈希化。
$ openssl dgst -sha256 -binary rsa_plain.txt > rsa_plain.hash_sha256
哈希值是二進制格式的。
為了以防萬一,我們來查看一下內容。
$ openssl base64 -in rsa_plain.hash_sha256
tC3aKaEPmtrdoDX7TdqA+5pbL324Tc4qOzQ2nrO0ncA=
現在,基於哈希值進行簽名。
$ openssl pkeyutl -sign -inkey rsa_private.pem -in rsa_plain.hash_sha256 -out rsa_plain.sig -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss
一個名為rsa_plain.sig的檔案已經被創建。
到目前為止是愛麗絲的作業。
(公開金鑰、文本消息和簽名文件需要以某種方式發送給鮑勃)
接下來是鮑勃的作業。
首先,將文本消息進行哈希化。
$ openssl dgst -sha256 -binary rsa_plain.txt > rsa_plain_bob.hash_sha256
接下來對簽名進行驗證。
$ openssl pkeyutl -verify -pubin -inkey rsa_public.pem -in rsa_plain_bob.hash_sha256 -sigfile rsa_plain.sig -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss
Signature Verified Successfully
得到「Signature Verified Successfully」,所以可以驗證簽名是正確的。太好了。
我們用簡單的圖示來說明非對稱加密的鍵共識(密鑰共享)。
(同樣,這部分也較為複雜)

這次又是愛麗絲與鮑勃的主題。
鍵共識(密鑰共享)是基於非對稱加密生成共通金鑰。
首先,愛麗絲和鮑勃分別創建自己的私有金鑰和公開金鑰。
(A私有金鑰…愛麗絲的私有金鑰,A公開金鑰…愛麗絲的公開金鑰,B私有金鑰…鮑勃的私有金鑰,B公開金鑰…鮑勃的公開金鑰)
接著,愛麗絲將自己的公開金鑰(A公開金鑰)交給鮑勃,而鮑勃也將自己的公開金鑰(B公開金鑰)交給愛麗絲。
然後,愛麗絲用自己的私有金鑰(A私有金鑰)和鮑勃的公開金鑰(B公開金鑰)生成共通金鑰。
同理,鮑勃則用自己的私有金鑰(B私有金鑰)和愛麗絲的公開金鑰(A公開金鑰)生成共通金鑰。
如此形成的共通金鑰,竟然是相同的!
(為什麼會如此呢?也許你會疑惑,但從數學的角度來看,正是這樣的道理)
※這部分屬於專業性內容,我將省略。
愛麗絲將文本消息使用共通金鑰進行加密。
鮑勃使用共通金鑰將加密後的資料進行解密。
我們來試試openssl進行鍵共識(以及加密與解密)。
鍵共識需要愛麗絲和鮑勃各自執行幾項作業(請注意不要混淆)。
首先是愛麗絲的作業。
生成文本消息。
$ echo "My name is Alice." > rsa_plain.txt
$ cat rsa_plain.txt
My name is Alice.
生成私有金鑰。
$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out alice_private.pem
生成公開金鑰。
$ openssl pkey -in alice_private.pem -pubout -out alice_public.pem
接下來是鮑勃的作業。
生成私有金鑰。
$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:prime256v1 -out bob_private.pem
生成公開金鑰。
$ openssl pkey -in bob_private.pem -pubout -out bob_public.pem
愛麗絲的公開金鑰傳送給鮑勃,鮑勃的公開金鑰則傳送給愛麗絲。
(傳送方式由你們自行決定,反正是公開金鑰)。
然後再回到愛麗絲的作業。
生成共通金鑰(的基礎資訊)。
$ openssl pkeyutl -derive -inkey alice_private.pem -peerkey bob_public.pem -out alice_secret.bin
接下來是鮑勃的作業。
同樣生成共通金鑰(的基礎資訊)。
$ openssl pkeyutl -derive -inkey bob_private.pem -peerkey alice_public.pem -out bob_secret.bin
這是愛麗絲的作業。
生成共通金鑰與IV。
$ openssl dgst -sha256 -binary alice_secret.bin > aes_key.bin
$ openssl dgst -sha256 -binary -mac HMAC -macopt hexkey:00 alice_secret.bin | head -c 16 > aes_iv.bin
這是鮑勃的作業。
生成共通金鑰與IV。
$ openssl dgst -sha256 -binary bob_secret.bin > aes_key.bin
$ openssl dgst -sha256 -binary -mac HMAC -macopt hexkey:00 bob_secret.bin | head -c 16 > aes_iv.bin
愛麗絲的作業。
將文本消息進行加密。
$ openssl enc -aes-256-cbc -e -in alice_plain.txt -out alice_cipher.bin -K "$(xxd -p -c 256 aes_key.bin)" -iv "$(xxd -p -c 256 aes_iv.bin)"
為了確認推測加密的成功。
$ cat alice_cipher.bin
uEۻƽo�/��� 9���cG�gװ�d(���f
(這條加密的消息需要以某種方式發送給鮑勃)
鮑勃的作業。
將文本消息進行解密。
$ openssl enc -aes-256-cbc -d -in alice_cipher.bin -out bob_decrypted.txt -K "$(xxd -p -c 256 aes_key.bin)" -iv "$(xxd -p -c 256 aes_iv.bin)"
確認消息是否成功解密。
$ cat bob_decrypted.txt
My name is Alice.
一切圓滿結束。
這次我們學習了(對稱加密與)非對稱加密的內容。
由於「公開金鑰加密」這個名稱,或許有些人認為這僅用於「加密與解密」,
但實際上,它在其他用途上也有應用。
互聯網上的加密通信,像是TLS和證書,都使用了這種非對稱加密(和對稱加密)。
對於系統工程師(尤其是涉及安全的人員)來說,這是一個非常重要的領域。
請一定要記住這一點。
(如果感興趣的人,可以參考更專門的書籍)。
目前正在考慮,「TLS」或「證書」呢。
這本身就是一個深奧的主題,希望能儘可能簡潔地進行解釋。