查看源代码 新旧 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 的调用。
有关可用算法的信息,请使用
由于 crypto_init
和 crypto_update
包括此功能,因此不需要 next_iv/2
和 next_iv/3
。
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>
请注意,StateEnc
和 StateDec
引用的内部数据会被调用 crypto_update/2 破坏性地更新。这是为了在与加密库接口的 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 名称。格式为 ALGORITM_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 |