🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

0.前言

從事安全(解決方案)工作已經二十多年了的前系統工程師。
我作為新人系統工程師在SIer開始工作的時候,
公司提供的電腦上並沒有安裝防病毒軟體。
(或許你會想這不可能,但那時候的安全意識就是這樣)

現在考慮到安全對策已成為經營課題之一,
我感受到,長時間的工作經歷,讓我意識到了許多事情。
(那時候的想法是「安全?那是什麼?」之類的…)

那麼,這次我們來聊聊安全的基礎之一「公開金鑰加密」。

1.對稱加密與非對稱加密的基礎

作為一般加密機制而著名的有兩種。「對稱加密」與「非對稱加密」。
在介紹非對稱加密之前,先來解釋對稱加密。

1-1.對稱加密

對稱加密是指加密和解密使用相同的金鑰(因為使用相同的金鑰,所以稱為對稱加密)。

我們用簡單的圖示來說明。

image.png

這次的主角是愛麗絲與鮑勃。
左邊的愛麗絲用對稱金鑰加密一條文本消息,右邊的鮑勃則用(相同的)對稱金鑰對接收到的加密消息進行解密。

如果沒有對稱金鑰,就會出現以下狀況。
・愛麗絲無法加密文本消息
・鮑勃無法解密加密消息

1-1-1.針對技術人員:openssl的執行結果

我們來試試使用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.

恢復成功,看來一切正常。

1-1-2.對稱加密的挑戰

對了,對稱加密有一個挑戰。
那是什麼呢?
(這個理由正是連結到非對稱加密的根本原因)

那就是「金鑰的傳遞(密鑰配送)」問題。

在對稱加密中,如果沒有金鑰,就無法進行加密和解密。因此,必須以某種方式和對方共享金鑰。

那麼,如何安全地傳遞金鑰呢?
直接將其作為郵件附加檔,這樣做是危險的對吧?
那麼,是否要「加密後再附加」呢??
那麼,為了加密和解密,需要的金鑰又如何共享呢???

這樣一來,似乎就進入了一個迷宮…
Ohhh,真是麻煩…

以前的人想到了這個問題。認為需要一種新的加密方式。
那就是非對稱加密。
(加密有其歷史)

1-2.非對稱加密

非對稱加密是指加密和解密使用不同的金鑰。

我們用簡單的圖示來說明。

image.png

同樣是愛麗絲與鮑勃。
左邊的愛麗絲用公開金鑰對文本消息進行加密,右邊的鮑勃使用私有金鑰解密接收到的加密消息。

這裡的重點是,所使用的金鑰在加密和解密時是不同的。
(加密使用公開金鑰,解密使用私有金鑰)

1-2-1.非對稱加密的優勢

這種非對稱加密,解決了剛才提到的對稱加密的挑戰。
怎麼說呢,這個「公開金鑰」具有加密的功能,但不具解密的功能。因此,無需擔心它被偷取而不必安全保護。

因此,無需為金鑰的傳遞(密鑰配送)而煩惱(不必擔心如何安全地配送)。

1-2-2.針對技術人員:openssl的執行結果

同樣的,我們也試試使用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.

成功解密,太好了。

2. 非對稱加密有三種形式

至此,我們已經說明了對稱加密和非對稱加密。

非對稱加密的特性是

  • 使用公開金鑰加密
  • 使用私有金鑰解密

但是,其實非對稱加密還有其他用途。

2-1. 三種面向的非對稱加密

其實,非對稱加密有三種面向。
分別是:

  • 加密(保密性)
  • 簽名
  • 鍵共識(密鑰共享)

2-1-1. 加密(保密性)

非對稱加密的第一個面向是「加密」。也可以稱為「保密性」。
顧名思義,就是用來進行「加密」的方式,
正如先前所說的「使用公開金鑰加密,使用私有金鑰解密」。

一般來說,大概大家都認為這是最知名的「加密」方式。
(但實際上,使用非對稱加密進行「加密」的案例逐漸減少,特別是系統工程師應該要內心記住這一點)

2-1-2.簽名

非對稱加密的第二個面向是「簽名」。
後面會用圖示來說明。

2-1-3.鍵共識(密鑰共享)

非對稱加密的第三個面向是「鍵共識(密鑰共享)」。
這是一種稍有不同的使用方式。

「加密」與「簽名」中,一方持有私有金鑰,另一方持有公開金鑰。
但在「鍵共識(密鑰共享)」中,雙方都持有私有金鑰和公開金鑰。
而這樣的狀況是雙方共同擁有相同的對稱金鑰(共享)的機制!

接下來我們會用圖示來進一步解釋。

2-2.非對稱加密的簽名

我們用簡單的圖示來說明非對稱加密的簽名。
(雖然這部分稍微複雜一些)

image.png

還是那句話,這次的主角是愛麗絲與鮑勃。
左邊的愛麗絲根據文本消息生成簽名。
她不是直接對消息簽名,而是將消息先哈希化,再用私有金鑰對該哈希值進行簽名。

右邊的鮑勃獲取消息和簽名,並根據公開金鑰進行簽名驗證。如果簽名正確則確認無誤,若簽名錯誤則被視為無效。

2-2-1.針對技術人員:openssl的執行結果

同樣,我們來使用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」,所以可以驗證簽名是正確的。太好了。

2-3.非對稱加密的鍵共識(密鑰共享)

我們用簡單的圖示來說明非對稱加密的鍵共識(密鑰共享)。
(同樣,這部分也較為複雜)

image.png

這次又是愛麗絲與鮑勃的主題。

鍵共識(密鑰共享)是基於非對稱加密生成共通金鑰。

首先,愛麗絲和鮑勃分別創建自己的私有金鑰和公開金鑰。
(A私有金鑰…愛麗絲的私有金鑰,A公開金鑰…愛麗絲的公開金鑰,B私有金鑰…鮑勃的私有金鑰,B公開金鑰…鮑勃的公開金鑰)

接著,愛麗絲將自己的公開金鑰(A公開金鑰)交給鮑勃,而鮑勃也將自己的公開金鑰(B公開金鑰)交給愛麗絲。

然後,愛麗絲用自己的私有金鑰(A私有金鑰)和鮑勃的公開金鑰(B公開金鑰)生成共通金鑰。
同理,鮑勃則用自己的私有金鑰(B私有金鑰)和愛麗絲的公開金鑰(A公開金鑰)生成共通金鑰。

如此形成的共通金鑰,竟然是相同的!
(為什麼會如此呢?也許你會疑惑,但從數學的角度來看,正是這樣的道理)
※這部分屬於專業性內容,我將省略。

愛麗絲將文本消息使用共通金鑰進行加密。
鮑勃使用共通金鑰將加密後的資料進行解密。

2-3-1.針對技術人員:openssl的執行結果

我們來試試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.

一切圓滿結束。

3.結語

這次我們學習了(對稱加密與)非對稱加密的內容。

由於「公開金鑰加密」這個名稱,或許有些人認為這僅用於「加密與解密」,
但實際上,它在其他用途上也有應用。

互聯網上的加密通信,像是TLS和證書,都使用了這種非對稱加密(和對稱加密)。

對於系統工程師(尤其是涉及安全的人員)來說,這是一個非常重要的領域。
請一定要記住這一點。
(如果感興趣的人,可以參考更專門的書籍)。

3-1.下次預告?

目前正在考慮,「TLS」或「證書」呢。
這本身就是一個深奧的主題,希望能儘可能簡潔地進行解釋。

97.參考文獻

98.更新歷史

  • 2026.02.13 初版

99.EoF(檔案結尾)


原文出處:https://qiita.com/peridotan/items/441f4c6a467dae69583a


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝19   💬3  
490
🥈
我愛JS
📝1   💬5   ❤️2
65
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付