檢視原始碼 新舊 API
本章描述了加密和解密的新 API。
背景
CRYPTO 應用程式在其生命週期中不斷發展。由於 OpenSSL 密碼函式庫也多次更改了 API,因此 CRYPTO 應用程式的部分內部使用非常舊的 API,而其他部分則使用最新的 API。例如,密碼名稱的內部定義有點難以維護。
結果發現,以新的方式(稍後會詳細介紹)使用舊的 API,同時保持向後兼容性是不可能的。特別是當需要更精確的錯誤訊息時,它無法與舊標準結合使用。
因此,舊的 API(請參閱下一節)目前仍保留,但在內部以新的基本元素實現。
舊的 API
舊的函式 - 從 23.0 開始棄用,並從 OTP 24.0 移除 - 用於密碼
block_encrypt/3
block_encrypt/4
block_decrypt/3
block_decrypt/4
stream_init/2
stream_init/3
stream_encrypt/2
stream_decrypt/2
next_iv/2
next_iv/3
用於支援演算法的列表
supports/0
以及用於 MAC(訊息驗證碼)
cmac/3
cmac/4
hmac/3
hmac/4
hmac_init/2
hmac_update/2
hmac_final/1
hmac_final_n/2
poly1305/2
新的 API
加密和解密
用於加密或解密單個二進制檔案的新函式為
在這些函式中,首先建立並使用密碼類型、金鑰和可能存在的其他資料初始化內部加密狀態。然後加密或解密單個二進制檔案,解除分配加密狀態,並傳回加密操作的結果。
crypto_one_time_aead
函式用於 ccm
或 gcm
模式的密碼,以及用於密碼 chacha20-poly1305
。
對於重複加密或解密分為多部分的文字,其中內部加密狀態初始化一次,然後使用相同的狀態加密或解密多個二進制檔案,則使用以下函式
crypto_init
初始化內部密碼狀態,而一次或多次呼叫 crypto_update
則執行實際的加密或解密。請注意,由於其性質,無法以這種方式處理 AEAD 密碼。
一個需要這些函式的例子是處理 TLS 協定時。
如果未啟用填充,則可以排除對 crypto_final/1 的呼叫。
有關可用演算法的資訊,請使用
next_iv/2
和 next_iv/3
並不需要,因為 crypto_init
和 crypto_update
包含此功能。
MAC (訊息驗證碼)
用於計算單個文字的 MAC 的新函式為
對於計算分為多部分的文字的 MAC,請使用
新 API 的範例
crypto_init/4 和 crypto_update/2 的範例
函式 crypto_init/4 和 crypto_update/2 旨在用於加密或解密一系列區塊。首先,呼叫一次 crypto_init/4
來初始化加密內容。一次或多次呼叫 crypto_update/2
則針對每個區塊執行實際的加密或解密。
此範例首先顯示兩個區塊的加密,然後顯示密文的解密,但分為三個區塊只是為了顯示對於某些密碼來說,可以針對明文和密文使用不同的區塊劃分方式
1> crypto:start().
ok
2> Key = <<1:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
3> IV = <<0:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
4> StateEnc = crypto:crypto_init(aes_128_ctr, Key, IV, true). % encrypt -> true
#Ref<0.3768901617.1128660993.124047>
5> crypto:crypto_update(StateEnc, <<"First bytes">>).
<<67,44,216,166,25,130,203,5,66,6,162>>
6> crypto:crypto_update(StateEnc, <<"Second bytes">>).
<<16,79,94,115,234,197,94,253,16,144,151,41>>
7>
7> StateDec = crypto:crypto_init(aes_128_ctr, Key, IV, false). % decrypt -> false
#Ref<0.3768901617.1128660994.124255>
8> crypto:crypto_update(StateDec, <<67,44,216,166,25,130,203>>).
<<"First b">>
9> crypto:crypto_update(StateDec, <<5,66,6,162,16,79,94,115,234,197,
94,253,16,144,151>>).
<<"ytesSecond byte">>
10> crypto:crypto_update(StateDec, <<41>>).
<<"s">>
11>
請注意,呼叫 crypto_update/2 會破壞性地更新 StateEnc
和 StateDec
參考的內部資料。這是為了在與密碼函式庫介面的 nif 呼叫中節省時間。在迴圈中,如果狀態儲存在迴圈的狀態中,它還可以為每個加密操作節省一次迴圈狀態的更新。
例如,一個簡單的伺服器接收要加密的文字部分,並將結果傳回給傳送者(Requester
)
encode(Crypto, Key, IV) ->
crypto_loop(crypto:crypto_init(Crypto, Key, IV, true)).
crypto_loop(State) ->
receive
{Text, Requester} ->
Requester ! crypto:crypto_update(State, Text),
loop(State)
end.
crypto_one_time/5 的範例
與 上一節 中的範例相同,但現在呼叫一次 crypto_one_time/5
1> Key = <<1:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
2> IV = <<0:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
3> Txt = [<<"First bytes">>,<<"Second bytes">>].
[<<"First bytes">>,<<"Second bytes">>]
4> crypto:crypto_one_time(aes_128_ctr, Key, IV, Txt, true).
<<67,44,216,166,25,130,203,5,66,6,162,16,79,94,115,234,
197,94,253,16,144,151,41>>
5>
[<<"First bytes">>,<<"Second bytes">>]
當然可以是一個單個二進制檔案:<<"First bytesSecond bytes">>
。
crypto_one_time_aead/6 的範例
與 上一節 中的範例相同,但現在呼叫一次 crypto_one_time_aead/6
1> Key = <<1:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
2> IV = <<0:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>
3> Txt = [<<"First bytes">>,<<"Second bytes">>].
[<<"First bytes">>,<<"Second bytes">>]
4> AAD = <<"Some additional auth data">>.
<<"Some additional auth data">>
5> crypto:crypto_one_time_aead(aes_128_gcm, Key, IV, Txt, AAD, true).
{<<240,130,38,96,130,241,189,52,3,190,179,213,132,1,72,
192,103,176,90,104,15,71,158>>,
<<131,47,45,91,142,85,9,244,21,141,214,71,31,135,2,155>>}
6>
[<<"First bytes">>,<<"Second bytes">>]
當然可以是一個單個二進制檔案:<<"First bytesSecond bytes">>
。
mac_init mac_update 和 mac_final 的範例
1> Key = <<1:128>>.
<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1>>
2> StateMac = crypto:mac_init(cmac, aes_128_cbc, Key).
#Ref<0.2424664121.2781478916.232610>
3> crypto:mac_update(StateMac, <<"First bytes">>).
#Ref<0.2424664121.2781478916.232610>
4> crypto:mac_update(StateMac, " ").
#Ref<0.2424664121.2781478916.232610>
5> crypto:mac_update(StateMac, <<"last bytes">>).
#Ref<0.2424664121.2781478916.232610>
6> crypto:mac_final(StateMac).
<<68,191,219,128,84,77,11,193,197,238,107,6,214,141,160,
249>>
7>
並將結果與此範例的單一計算進行比較
7> crypto:mac(cmac, aes_128_cbc, Key, "First bytes last bytes").
<<68,191,219,128,84,77,11,193,197,238,107,6,214,141,160,
249>>
8> v(7) == v(6).
true
9>
已淘汰的密碼名稱
下表列出了第一欄中已淘汰的密碼名稱,並在第二欄中建議了替代名稱。
新名稱遵循 OpenSSL libcrypto 名稱。格式為 ALGORITHM_KEYSIZE_MODE。
演算法的範例包括 aes、chacha20 和 des。金鑰大小是位元數,模式的範例包括 cbc、ctr 和 gcm。模式後面可能會跟一個數字,具體取決於模式。一個範例是 ccm 模式,它有一個稱為 ccm8 的變體,其中所謂的標籤長度為 8 位元。
舊的名稱隨著時間的推移失去了任何通用的命名慣例,而新名稱現在引入了這些慣例。新名稱包括金鑰長度,這可以改進密碼應用程式較低層級中的錯誤檢查。
取代 | 使用 |
---|---|
aes_cbc128 | aes_128_cbc |
aes_cbc256 | aes_256_cbc |
aes_cbc | aes_128_cbc、aes_192_cbc、aes_256_cbc |
aes_ccm | aes_128_ccm、aes_192_ccm、aes_256_ccm |
aes_cfb128 | aes_128_cfb128、aes_192_cfb128、aes_256_cfb128 |
aes_cfb8 | aes_128_cfb8、aes_192_cfb8、aes_256_cfb8 |
aes_ctr | aes_128_ctr、aes_192_ctr、aes_256_ctr |
aes_gcm | aes_128_gcm、aes_192_gcm、aes_256_gcm |
des3_cbc | des_ede3_cbc |
des3_cbf | des_ede3_cfb |
des3_cfb | des_ede3_cfb |
des_ede3 | des_ede3_cbc |
des_ede3_cbf | des_ede3_cfb |