核心加密API架構

密碼演算法型別

核心加密API為以下密碼型別提供不同的API呼叫:

  • 對稱密碼

  • AEAD密碼

  • 訊息摘要,包括帶金鑰的訊息摘要

  • 隨機數生成

  • 使用者空間介面

密碼和模板

核心加密API提供單塊密碼和訊息摘要的實現。此外,核心加密API還提供許多“模板”,可以與單塊密碼和訊息摘要結合使用。模板包括所有型別的塊鏈模式、HMAC機制等。

單塊密碼和訊息摘要可以直接被呼叫者使用,也可以與模板一起呼叫,以形成多塊密碼或帶金鑰的訊息摘要。

一個單塊密碼甚至可以與多個模板一起呼叫。但是,模板不能在沒有單塊密碼的情況下使用。

參見/proc/crypto並搜尋“name”。例如:

  • aes

  • ecb(aes)

  • cmac(aes)

  • ccm(aes)

  • rfc4106(gcm(aes))

  • sha1

  • hmac(sha1)

  • authenc(hmac(sha1),cbc(aes))

在這些示例中,“aes”和“sha1”是密碼,所有其他都是模板。

同步和非同步操作

核心加密API提供同步和非同步API操作。

當使用同步API操作時,呼叫者會呼叫一個密碼操作,該操作由核心加密API同步執行。這意味著,呼叫者會等待直到密碼操作完成。因此,核心加密API呼叫就像常規函式呼叫一樣工作。對於同步操作,API呼叫的集合很小,並且在概念上類似於任何其他加密庫。

非同步操作由核心加密API提供,這意味著密碼操作的呼叫將幾乎立即完成。該呼叫會觸發密碼操作,但它不會發出完成訊號。在呼叫密碼操作之前,呼叫者必須提供一個回撥函式,核心加密API可以呼叫該函式來發出密碼操作完成的訊號。此外,呼叫者必須透過對其資料應用適當的鎖定來確保其可以處理此類非同步事件。核心加密API不執行任何特殊的序列化操作來保護呼叫者的資料完整性。

加密API密碼引用和優先順序

呼叫者透過字串引用密碼。該字串具有以下語義:

template(single block cipher)

其中“template”和“single block cipher”分別是前面提到的模板和單塊密碼。如果適用,其他模板可以包含其他模板,例如:

template1(template2(single block cipher)))

核心加密API可能提供模板或單塊密碼的多種實現。例如,在較新的Intel硬體上,AES有以下實現:AES-NI、彙編器實現或純C。現在,當使用字串“aes”與核心加密API時,會使用哪種密碼實現?這個問題的答案是核心加密API為每個密碼實現分配的優先順序數字。當呼叫者在初始化密碼控制代碼時使用該字串引用密碼時,核心加密API會查詢所有提供該名稱實現的實現,並選擇優先順序最高的實現。

現在,呼叫者可能需要引用特定的密碼實現,因此不想依賴基於優先順序的選擇。為了適應這種情況,核心加密API允許密碼實現除了通用名稱外,還註冊一個唯一名稱。當使用該唯一名稱時,呼叫者因此始終可以確保引用預期的密碼實現。

/proc/crypto中列出了可用密碼列表。然而,該列表並未指定模板和密碼的所有可能組合。/proc/crypto中列出的每個塊可能包含以下資訊——如果以下列出的某個元件不適用於密碼,則不顯示:

  • name:密碼的通用名稱,受優先順序選擇的影響——該名稱可用於密碼分配API呼叫(上面列出的所有名稱都是此類通用名稱的示例)

  • driver:密碼的唯一名稱——該名稱可用於密碼分配API呼叫

  • module:提供密碼實現的核心模組(靜態連結密碼則為“kernel”)

  • priority:密碼實現的優先順序值

  • refcnt:相應密碼的引用計數(即當前使用該密碼的消費者數量)

  • selftest:指定密碼的自檢是否透過

  • type

    • skcipher 用於對稱金鑰密碼

    • cipher 用於可與附加模板一起使用的單塊密碼

    • shash 用於同步訊息摘要

    • ahash 用於非同步訊息摘要

    • aead 用於AEAD密碼型別

    • compression 用於壓縮型別轉換

    • rng 用於隨機數生成器

    • kpp 用於金鑰協商協議原語 (KPP) 密碼,如ECDH或DH實現

  • blocksize:密碼的塊大小(以位元組為單位)

  • keysize:金鑰大小(以位元組為單位)

  • ivsize:IV大小(以位元組為單位)

  • seedsize:隨機數生成器所需的種子資料大小

  • digestsize:訊息摘要的輸出大小

  • geniv:IV生成器(已廢棄)

金鑰大小

當分配密碼控制代碼時,呼叫者只指定密碼型別。然而,對稱密碼通常支援多種金鑰大小(例如AES-128 vs. AES-192 vs. AES-256)。這些金鑰大小由提供的金鑰長度決定。因此,核心加密API不提供單獨的方法來選擇特定的對稱密碼金鑰大小。

密碼分配型別和掩碼

不同的密碼控制代碼分配函式允許指定型別和掩碼標誌。這兩個引數具有以下含義(因此在後續部分中不再贅述)。

型別標誌指定密碼演算法的型別。當呼叫者希望預設處理時,通常提供0。否則,呼叫者可以提供以下與上述密碼型別匹配的選擇:

  • CRYPTO_ALG_TYPE_CIPHER 單塊密碼

  • CRYPTO_ALG_TYPE_AEAD 帶關聯資料的認證加密 (MAC)

  • CRYPTO_ALG_TYPE_KPP 金鑰協商協議原語 (KPP),如ECDH或DH實現

  • CRYPTO_ALG_TYPE_HASH 原始訊息摘要

  • CRYPTO_ALG_TYPE_SHASH 同步多塊雜湊

  • CRYPTO_ALG_TYPE_AHASH 非同步多塊雜湊

  • CRYPTO_ALG_TYPE_RNG 隨機數生成

  • CRYPTO_ALG_TYPE_AKCIPHER 非對稱密碼

  • CRYPTO_ALG_TYPE_SIG 非對稱簽名

  • CRYPTO_ALG_TYPE_PCOMPRESS CRYPTO_ALG_TYPE_COMPRESS 的增強版本,允許分段壓縮/解壓縮,而不是僅在一個段上執行操作。一旦現有消費者完成轉換,CRYPTO_ALG_TYPE_PCOMPRESS 旨在取代 CRYPTO_ALG_TYPE_COMPRESS。

掩碼標誌限制密碼的型別。唯一允許的標誌是CRYPTO_ALG_ASYNC,用於將密碼查詢功能限制為非同步密碼。通常,呼叫者為掩碼標誌提供0。

當呼叫者提供掩碼和型別規範時,它限制了核心加密API可以為給定密碼名稱執行的合適密碼實現的搜尋。這意味著,即使呼叫者在初始化呼叫期間使用的密碼名稱存在,核心加密API也可能由於使用的型別和掩碼欄位而不會選擇它。

核心加密API的內部結構

核心加密API具有內部結構,其中密碼實現可能使用許多層和間接方式。本節將幫助澄清核心加密API如何使用各種元件來實現完整的密碼。

以下小節根據現有密碼實現解釋內部結構。第一節解決了最複雜的場景,而所有其他場景都構成其邏輯子集。

通用AEAD密碼結構

以下ASCII藝術圖分解了使用帶有自動IV生成的AEAD密碼時核心加密API的層。所示示例由IPSEC層使用。

對於AEAD密碼的其他用例,ASCII藝術圖也適用,但呼叫者可能不會將AEAD密碼與單獨的IV生成器一起使用。在這種情況下,呼叫者必須生成IV。

所示示例根據通用C實現(gcm.c、aes-generic.c、ctr.c、ghash-generic.c、seqiv.c)分解了GCM(AES)的AEAD密碼。通用實現作為示例,展示了核心加密API的完整邏輯。

一些簡化的密碼實現(如AES-NI)可能會提供合併了核心加密API檢視中無法再分解為層的方面的實現。在AES-NI實現的情況下,CTR模式、GHASH實現和AES密碼都合併到一個註冊到核心加密API的密碼實現中。在這種情況下,以下ASCII藝術圖描述的概念也適用。然而,核心加密API不再將GCM分解為各個子元件。

以下ASCII藝術圖中的每個塊都是從核心加密API獲得的獨立密碼例項。呼叫者或其他塊使用核心加密API為密碼實現型別定義的API函式訪問每個塊。

下面的塊指示了密碼型別以及密碼中實現的特定邏輯。

ASCII藝術圖還指示了呼叫結構,即誰呼叫哪個元件。箭頭指向被呼叫的塊,呼叫者使用適用於為該塊指定的密碼型別的API。

kernel crypto API                                |   IPSEC Layer
                                                 |
+-----------+                                    |
|           |            (1)
|   aead    | <-----------------------------------  esp_output
|  (seqiv)  | ---+
+-----------+    |
                 | (2)
+-----------+    |
|           | <--+                (2)
|   aead    | <-----------------------------------  esp_input
|   (gcm)   | ------------+
+-----------+             |
      | (3)               | (5)
      v                   v
+-----------+       +-----------+
|           |       |           |
|  skcipher |       |   ahash   |
|   (ctr)   | ---+  |  (ghash)  |
+-----------+    |  +-----------+
                 |
+-----------+    | (4)
|           | <--+
|   cipher  |
|   (aes)   |
+-----------+

當IPSEC層使用esp_output函式觸發加密操作時,以下呼叫序列適用。在配置期間,管理員將seqiv(rfc4106(gcm(aes)))設定為ESP的密碼。以下呼叫序列在上面的ASCII藝術圖中描述:

  1. esp_output() 呼叫 crypto_aead_encrypt() 來觸發帶IV生成器的AEAD密碼的加密操作。

    SEQIV生成IV。

  2. 現在,SEQIV使用AEAD API函式呼叫來呼叫關聯的AEAD密碼。在我們的例子中,在例項化SEQIV期間,GCM的密碼控制代碼被提供給SEQIV。這意味著SEQIV使用GCM密碼控制代碼呼叫AEAD密碼操作。

    在GCM控制代碼例項化期間,CTR(AES)和GHASH密碼被例項化。CTR(AES)和GHASH的密碼控制代碼被保留以備後用。

    GCM實現負責以正確的方式呼叫CTR模式AES和GHASH密碼,以實現GCM規範。

  3. GCM AEAD密碼型別實現現在使用已例項化的CTR(AES)密碼控制代碼呼叫SKCIPHER API。

    在CTR(AES)密碼例項化期間,AES的CIPHER型別實現被例項化。AES的密碼控制代碼被保留。

    這意味著CTR(AES)的SKCIPHER實現只實現CTR塊鏈模式。在執行塊鏈操作後,AES的CIPHER實現被呼叫。

  4. CTR(AES)的SKCIPHER現在使用AES密碼控制代碼呼叫CIPHER API來加密一個塊。

  5. GCM AEAD實現也透過AHASH API呼叫GHASH密碼實現。

當IPSEC層觸發esp_input()函式時,遵循相同的呼叫序列,唯一區別是操作從步驟(2)開始。

通用塊密碼結構

通用塊密碼遵循與上面ASCII藝術圖所示相同的概念。

例如,CBC(AES)是使用cbc.c和aes-generic.c實現的。上面的ASCII藝術圖也適用,區別僅在於只使用了步驟(4),並且SKCIPHER塊鏈模式是CBC。

通用帶金鑰訊息摘要結構

帶金鑰訊息摘要實現再次遵循與上面ASCII藝術圖所示相同的概念。

例如,HMAC(SHA256)是使用hmac.c和sha256_generic.c實現的。以下ASCII藝術圖說明了該實現:

kernel crypto API            |       Caller
                             |
+-----------+         (1)    |
|           | <------------------  some_function
|   ahash   |
|   (hmac)  | ---+
+-----------+    |
                 | (2)
+-----------+    |
|           | <--+
|   shash   |
|  (sha256) |
+-----------+

當呼叫者觸發HMAC操作時,以下呼叫序列適用:

  1. 呼叫者呼叫AHASH API函式。HMAC實現根據需要執行其操作。

    在HMAC密碼初始化期間,SHA256的SHASH密碼型別被例項化。SHA256例項的密碼控制代碼被保留。

    HMAC實現有時需要一個SHA256操作,此時使用SHA256密碼控制代碼。

  2. HMAC例項現在使用SHA256密碼控制代碼呼叫SHASH API來計算訊息摘要。