密碼學 - SignedData 與 EnvelopedData

在數位資訊交換的時代,如何確保訊息的「完整性」、「來源可信度」以及「機密性」是至關重要的課題。公開金鑰基礎建設(PKI)中的密碼學訊息語法(Cryptographic Message Syntax, CMS),其前身為 PKCS#7 標準,定義了多種資料保護的結構,其中 SignedData 和 EnvelopedData 是兩個最核心也最常被應用的概念。

簡單來說,您可以將 SignedData 想像成一份蓋了數位印鑑(簽章)的公開文件,而 EnvelopedData 則像是一個只有指定收件人才能打開的機密信封。image 123

ASN.1:資料結構的通用語言

在深入了解 SignedData 和 EnvelopedData 的細節之前,我們需要先認識定義這些結構的語言:ASN.1 (Abstract Syntax Notation One)。

ASN.1 是一套標準,用來定義資料結構的抽象語法,它就像是設計資料格式的「藍圖」。然而,藍圖本身並不能直接用於傳輸,還需要一套「施工規範」將其轉換為實際的位元組序列,這套規範就是編碼規則,其中最常見的就是 **DER (Distinguished Encoding Rules)**。

簡單來說:

  • ASN.1:定義了「有哪些欄位」、「欄位的型別是什麼(例如整數、字串)」以及「欄位的順序」。
  • DER:提供了一種明確、無歧義的方式,將 ASN.1 定義的結構轉換成電腦可以讀懂的二進位資料。

所有 CMS 的結構,包括 SignedData 和 EnvelopedData,都是透過 ASN.1 來進行標準化定義的。這確保了無論在哪個平台或系統上,大家都能用同樣的方式去解析與建立這些安全的訊息格式。

更詳細的 ASN.1 資訊,可以參考 密碼學 - ASN.1 DER Length Decoding

SignedData:驗證文件來源與完整性

SignedData 的主要目的在於提供兩大保證:

  1. 資料完整性(Integrity):確保資料在傳輸過程中沒有被竄改。
  2. 身分驗證(Authentication):證明資料確實是由某個特定的簽署者所發出,防止他人冒充。

值得注意的是,SignedData 本身不提供資料的機密性,也就是說,被簽署的內容本身是公開可讀的。

運作原理

SignedData 的運作流程如下圖所示,這是一個「先摘要,後加密」的過程:

  1. 產生摘要(Digest):系統會使用一個單向的雜湊演算法(如 SHA-256)對原始資料進行運算,產生一組固定長度的「訊息摘要(Message Digest)」。這就像是文件的指紋,任何對文件的微小改動都會導致完全不同的指紋。
  2. 產生簽章(Signature):簽署者使用自己的私鑰(Private Key),對剛剛產生的訊息摘要(或連同一些認證屬性)進行加密。這個加密後的結果就是「數位簽章」。
  3. 封裝:最後,將「原始資料」、「數位簽章」以及「簽署者的數位憑證(包含公鑰)」一同封裝成一個 SignedData 物件。

驗證流程

當收件人收到這份 SignedData 後,會執行以下步驟來驗證其有效性:

  1. 使用簽署者憑證中的公鑰(Public Key)來解密數位簽章,還原出原始的訊息摘要(我們稱之為摘要A)。
  2. 使用與簽署者相同的雜湊演算法,對收到的原始資料重新計算一次,產生一個新的訊息摘要(我們稱之為摘要B)。
  3. 比對摘要A與摘要B是否完全一致。

如果兩者相符,則代表:

  • 資料未被竄改:因為只要資料有任何變動,摘要B就會不同。
  • 簽署者身分正確:因為只有真正的簽署者才擁有能產生該簽章的私鑰,其他人無法偽造。

深入細節:簽章屬性 (Attributes)

為了讓簽章帶有更豐富的資訊,SignedData 的結構中可以包含兩種屬性:

  • 認證屬性 (Authenticated Attributes):這些屬性會和原始資料的摘要一起被簽署者簽署,因此受到同樣的保護,無法被竄改。常見的例子包括:
    • signingTime:標示簽署的確切時間。
    • contentType:指明被簽署的內容是什麼類型。
    • messageDigest:原始資料的摘要值本身也會被放在這裡,再次進行簽署,提供更強的保護。
  • 非認證屬性 (Unauthenticated Attributes):這些屬性是事後附加的,不會被簽章保護,任何人都可以修改或增刪。例如,counterSignature(反簽章),允許第三方在不影響原始簽章的情況下,對此簽章再次簽署,形成一種背書的效果。

EnvelopedData:保護資料的機密性

相對於 SignedData,EnvelopedData 的核心目標是資料機密性(Confidentiality)。它確保只有指定的收件人能夠讀取訊息內容,其他人即使截獲了資料也無法窺探其義。

運作原理

EnvelopedData 採用了混合式加密策略,巧妙地結合了對稱加密與非對稱加密的優點,流程如下:

  1. 產生對稱金鑰:系統會產生一把隨機、一次性的「對稱金鑰」(也稱為會話金鑰或 CEK, Content-Encryption Key)。
  2. 加密資料:使用這把對稱金鑰與高效的對稱加密演算法(如 AES)來加密原始資料。
  3. 加密金鑰:接著,使用收件人的公鑰(Public Key),透過非對稱加密演算法(如 RSA)來加密剛剛那把對稱金鑰。
  4. 封裝:最後,將「加密後的資料」和「加密後的對稱金鑰」封裝成一個 EnvelopedData 物件。

解密流程

當指定的收件人收到這份 EnvelopedData 後:

  1. 使用自己的私鑰(Private Key)來解密被加密過的對稱金鑰,取得原始的對稱金鑰。
  2. 使用這把還原的對稱金鑰,來解密主要的加密資料,從而讀取原始內容。

由於只有收件人擁有能解開對稱金鑰的私鑰,因此確保了只有他能閱讀這份文件,達到了信封的效果。

深入細節:多元的收件人格式 (RecipientInfo)

為了應對不同的金鑰管理情境,EnvelopedData 設計了非常彈性的收件人資訊格式 RecipientInfo。本文主要描述的是最常見的 KeyTransRecipientInfo(金鑰傳輸),也就是直接用收件人的 RSA 公鑰來加密對稱金鑰。

除此之外,標準還定義了其他類型,例如:

  • KeyAgreeRecipientInfo(金鑰協商):基於 Diffie-Hellman (DH) 或 Elliptic Curve Diffie-Hellman (ECDH) 等演算法。寄件人和收件人透過交換公開參數來「協商」出只有他們雙方知道的共享金鑰,再用此金鑰來加密或解密對稱金鑰。
  • KEKRecipientInfo(金鑰加密金鑰):適用於雙方已預先共享了一把「金鑰加密金鑰 (KEK)」的情境。寄件人直接用這把 KEK 來加密對稱金鑰。
  • PasswordRecipientInfo(密碼加密):從使用者輸入的密碼中衍生出一把金鑰,用來加密對稱金鑰。

這種彈性設計讓 EnvelopedData 可以適應各種不同的安全應用場景。

結合應用:SignedAndEnvelopedData

在許多高安全性的應用場景中(例如安全電子郵件 S/MIME 或金融交易),我們既需要驗證寄件人身分與資料完整性,也需要確保內容的機密性。這時,便可以將 SignedData 與 EnvelopedData 結合使用。

標準的作法是「先簽章,再加密」:

  1. 寄件人先將原始資料製作成一份 SignedData。
  2. 然後將整個 SignedData 物件視為新的資料,再對其進行加密,製作成一份 EnvelopedData。

如此一來,收件人收到後會先用自己的私鑰「拆開信封」(解密),得到一份完整的 SignedData,接著再用寄件人的公鑰「驗證簽章」。這個流程同時滿足了身分驗證、資料完整性與機密性的所有需求。

總結比較

特性SignedData (數位簽章)EnvelopedData (數位信封)
主要目的完整性、身分驗證、不可否認性機密性
加密對象訊息摘要 (Message Digest)原始資料本身
使用的金鑰(加密)寄件人的私鑰隨機產生的對稱金鑰,再用收件人的公鑰加密此金鑰
使用的金鑰(解密/驗證)寄件人的公鑰收件人的私鑰
資料可見性內容公開可見內容被加密,無法直接讀取

透過理解 SignedData 和 EnvelopedData 的原理與應用,我們更能體會現代密碼學如何在數位世界中為我們的通訊安全保駕護航。

也許你也會想看看