开源、先进、易用 C 语言加密函数库 Libsodium 中文指南

您所在的位置:网站首页 开源加密算法有哪些 开源、先进、易用 C 语言加密函数库 Libsodium 中文指南

开源、先进、易用 C 语言加密函数库 Libsodium 中文指南

2024-07-10 03:50| 来源: 网络整理| 查看: 265

Libsodium 是一个开源、跨平台、跨语言的加密库,提供了一组简单易用的函数,大大简化了加密、散列、签名、鉴别、解密等复杂工作。支持许多种主流的加密算法和散列算法,包括 AES256-GCM 和 ChaCha20-Poly1305 两种 AEAD 加密方案。此外还提供了一系列方便实用的函数,可完成随机数的生成、大数的计算、编码和解码等辅助性工作。

源码:GitHub | 码云 文档:GitHub | 码云 | 官网 🧱 起步

执行以下命令,完成 Libsodium 的下载、解压、编译和安装。

1234567$ yum -y groupinstall "Development Tools" # apt install -y build-essential$ wget -N --no-check-certificate https://download.libsodium.org/libsodium/releases/libsodium-1.0.17.tar.gz$ tar -zxf libsodium-1.0.17.tar.gz$ cd libsodium-1.0.17$ ./configure$ make && make check$ make install

Libsodium 的动态链接库 lib*.so* 位于 /usr/local/lib 目录中。须将此目录设为动态库的搜寻目录之一,否则依赖于 Libsodium 的程序将无法运行。

12$ echo "/usr/local/lib" > /etc/ld.so.conf.d/usr-local-lib.conf$ ldconfig

在 /usr/local/lib/pkgconfig 目录中,可以找到文件 libsodium.pc。为了能够通过命令 pkg-config 获取编译和链接所需参数,须将此文件复制到 pkg-config 命令的搜寻目录中。

1$ cp /usr/local/lib/pkgconfig/libsodium.pc /usr/share/pkgconfig/

通过命令 pkg-config 获取编译和链接所需参数。

1234$ pkg-config --cflags libsodium-I/usr/local/include$ pkg-config --libs libsodium-L/usr/local/lib -lsodium

如果使用了 make,应当在 Makefile 文件中使用上述两条命令。

12CFLAGS = $(pkg-config --cflags libsodium)LDFLAGS = $(pkg-config --libs libsodium)

而在程序中,只需包含头文件 sodium.h 即可。

123456789#include int main(void){ if (sodium_init() == -1) { return 1; } ...}

在使用 Libsodium 的其他函数之前,必须先调用函数 sodium_init()。该函数不需要任何参数,返回 0 表示成功,返回 -1 表示失败,返回 1 则表示已经初始化过了。

📖 知识储备两种密码体制

当前有两种密码体制:一种称为对称密钥密码体制;另一种称为公钥密码体制。

在对称密钥密码体制中,加密和解密使用相同的密钥。密钥由通信双方事先约定。算法可以公开,而密钥需要保密。

公钥密码体制在加密和解密过程中使用不同的密钥。并且使用其中一个进行加密,则需要用另一个才能解密。这两个成对的密钥在使用时,一个密钥作为私钥,需要保密;另一个密钥作为公钥,可以公开。

对称加密算法

对称加密算法分为分组密码(又称块加密)和序列密码(又称流密码、流加密)两种。

著名的分组密码:DES、AES 常用的流密码:Salsa20、ChaCha20 MAC 报文鉴别码

MAC 是 Message Authentication Code 的缩写,即报文鉴别码。通常是经过加密的散列值。计算报文鉴别码的算法称为 MAC 算法。常用的 MAC 算法有:

GMAC CBC-MAC Poly1305 AE

AE 是 Authenticated encryption 的缩写。顾名思义,这种加密方案不仅能提供机密性,还能提供完整性。任何伪造或篡改都会被发现。

AE 实际上是对称加密算法和 MAC 算法的结合体。在加密一个报文时,需要一个密钥和一个不重数,加密后将得到密文和一个报文鉴别码。报文鉴别码须随同密文一起发送给接收方。

接收方收到报文鉴别码和密文后,须用相同的密钥和不重数才能进行解密。任何对密文和报文鉴别码的篡改都会导致解密失败。当然,只要确保密钥没有泄露,其他人也无法伪造出合法的密文和相应的报文鉴别码。

不重数,即不重复的数,不需要保密,通常是从 0 开始递增的计数器,位数足够多的时候也可以是随机数。密钥和不重数的结合,相当于一次一密,能有效抵御「重放攻击」。

AEAD

AEAD 是 Authenticated Encryption with Additional Data 的缩写。相比于 AE,AEAD 在加、解密时还可以选择性地给定一些没有保密性要求的「附加数据」,例如版本号、时间戳、报文的长度和编码方式等。这些附加数据会参与到报文鉴别码的计算中去,但不会被加密,也不会成为密文的一部分。附加数据可以随同密文一起发送。

常用的 AEAD 有以下两种:

AES256-GCM ChaCha20-Poly1305

Intel 在 2008 年推出新的指令集——AES-NI,为 AES 算法提供了硬件层面上的支持。但在其他平台(ARM)上,针对移动互联网优化的 ChaCha20 的速度大约是 AES 的三倍。

ChaCha20-Poly1305 最初在 2014 年提出,在 2015 年成为 IETF 标准,即 ChaCha20-Poly1305-IETF。后来,又通过对 ChaCha20 的改进,形成 XChaCha20-Poly1305-IETF。这一版本有望成为新的 IETF 标准,也是 Libsodium 目前首推的加密方案。

不同 AEAD 的密钥、不重数和报文鉴别码的长度(单位:位):

AEAD Key 密钥 Nonce 不重数 MAC 报文鉴别码 AES256-GCM 256 96 128 ChaCha20-Poly1305 256 64 128 ChaCha20-Poly1305-IETF 256 96 128 XChaCha20-Poly1305-IETF 256 192 128 🔐 Libsodium 对 ChaCha20-Poly1305 的支持

Libsodium 为 ChaCha20-Poly1305 的三种版本分别提供了三组函数:

crypto_aead_chacha20poly1305_*() crypto_aead_chacha20poly1305_ietf_*() crypto_aead_xchacha20poly1305_ietf_*()

这三组函数在用法上完全一致,因此只要掌握了其中一种,自然也就掌握了其余两种。

加密12345678910int crypto_aead_xchacha20poly1305_ietf_encrypt_detached(unsigned char *c, unsigned char *mac, unsigned long long *maclen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k);

函数 crypto_aead_xchacha20poly1305_ietf_encrypt_detached() 使用密钥 k 和不重数 npub 对 mlen 字节的报文 m 进行加密,并根据密文和 adlen 字节的附加数据 ad 计算报文鉴别码。密文将被写到 c,而报文鉴别码将被写到 mac,maclen 会被设为 mac 的长度。

密文和明文等长。而密钥、不重数、报文鉴别码的长度都是固定的,它们分别等于:

crypto_aead_xchacha20poly1305_ietf_KEYBYTES crypto_aead_xchacha20poly1305_ietf_NPUBBYTES crypto_aead_xchacha20poly1305_ietf_ABYTES

若没有关联的数据,则把 ad 设为 NULL,并把 adlen 设为 0。

此处 nsec 必须始终设为 NULL,下同。

123456789101112131415161718192021222324252627282930313233343536373839404142#include int main(void){ if (sodium_init() == -1) { return 1; } // 密钥 unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES] = "123456"; // 不重数 unsigned char npub[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = {0}; // 明文 int mlen = 5; unsigned char m[6] = "hello"; // 附加的数据 int adlen = 4; unsigned char ad[5] = "2020"; // 密文 unsigned char c[6]; // 报文鉴别码 unsigned char mac[crypto_aead_xchacha20poly1305_ietf_ABYTES]; unsigned long long maclen; // 加密 crypto_aead_xchacha20poly1305_ietf_encrypt_detached(c, mac, &maclen, m, mlen, ad, adlen, NULL, npub, k); // 获取密文和报文鉴别码的十六进制表示 char buf[1024]; sodium_bin2hex(buf, sizeof buf, c, 5); printf("Ciphertext: %s\n", buf); sodium_bin2hex(buf, sizeof buf, mac, maclen); printf("MAC: %s\n", buf); return 0;} 12Ciphertext: 5abc40d737MAC: 0be7cd4beaf9ec2a063170aab65fa5aa

函数 sodium_bin2hex() 是 Libsodium 提供的「辅助函数」,具体用法详见下文。

在密钥不变的情况下,不重数必须每次都不一样。建议用 randombytes_buf() 函数产生第一条报文的不重数,再用 sodium_increment() 函数对其进行递增。

解密

解密必须提供相同的密钥 k、不重数 npub 和附加数据 ad。

123456789int crypto_aead_xchacha20poly1305_ietf_decrypt_detached(unsigned char *m, unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *mac, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k);

函数 crypto_aead_xchacha20poly1305_ietf_decrypt_detached() 首先验证 c 中包含的 tag 是否合法。若函数返回 -1 表示验证未通过;若验证通过,则返回 0,并将解密得到的报文写到 m。

12345678910111213141516171819202122232425262728293031323334353637383940#include int main(void){ if (sodium_init() == -1) { return 1; } // 密钥 unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES] = "123456"; // 不重数 unsigned char npub[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = {0}; // 明文 unsigned char m[6]; // 附加的数据 int adlen = 4; unsigned char ad[5] = "2020"; // 密文 int clen = 5; unsigned char c[6]; sodium_hex2bin(c, clen, "5abc40d737", 10, NULL, NULL, NULL); // 报文鉴别码 unsigned char mac[crypto_aead_xchacha20poly1305_ietf_ABYTES]; sodium_hex2bin(mac, crypto_aead_xchacha20poly1305_ietf_ABYTES, "0be7cd4beaf9ec2a063170aab65fa5aa", 32, NULL, NULL, NULL); // 解密 crypto_aead_xchacha20poly1305_ietf_decrypt_detached(m, NULL, c, clen, mac, ad, adlen, npub, k); printf("Message: %s\n", m); return 0;} 1Message: hello 合并模式

以上这种将密文和报文鉴别码分开储存的方式称为分开模式。由于大多数需求都是将报文鉴别码直接追加到密文后面,即合并模式。因此,Libsodium 实际上为每种 AEAD 方案都提供两组函数:一组实现分开模式;另一组实现合并模式。

为合并模式设计的函数,相比于分开模式的函数,函数名少了后缀 _detached。

123456789int crypto_aead_xchacha20poly1305_ietf_encrypt(unsigned char *c, unsigned long long *clen_p, const unsigned char *m, unsigned long long mlen, const unsigned char *ad, unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k);

密钥、不重数、附加数据、明文等参数的含义同上。在合并模式下,报文鉴别码直接追加到密文后面,因此减少了 mac 和 maclen 两个参数,但参数 c 必须为报文鉴别码预留存储空间。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152#include int main(void){ if (sodium_init() == -1) { return 1; } // 密钥 unsigned char k[crypto_aead_xchacha20poly1305_ietf_KEYBYTES] = "123456"; // 不重数 unsigned char npub[crypto_aead_xchacha20poly1305_ietf_NPUBBYTES] = {0}; // 明文 int mlen = 5; unsigned char m[6] = "hello"; // 附加的数据 int adlen = 4; unsigned char ad[5] = "2020"; // 密文 unsigned char c1[6]; unsigned char c2[6 + crypto_aead_xchacha20poly1305_ietf_ABYTES]; unsigned long long clen; // 报文鉴别码 unsigned char mac[crypto_aead_xchacha20poly1305_ietf_ABYTES]; unsigned long long maclen; // 加密(分开模式) crypto_aead_xchacha20poly1305_ietf_encrypt_detached(c1, mac, &maclen, m, mlen, ad, adlen, NULL, npub, k); char buf[1024]; sodium_bin2hex(buf, sizeof buf, c1, 5); printf("Ciphertext: %s\n", buf); sodium_bin2hex(buf, sizeof buf, mac, maclen); printf("MAC: %s\n", buf); // 加密(合并模式) crypto_aead_xchacha20poly1305_ietf_encrypt(c2, &clen, m, mlen, ad, adlen, NULL, npub, k); sodium_bin2hex(buf, sizeof buf, c2, clen); printf("Ciphertext: %s\n", buf); return 0;} 123Ciphertext: 5abc40d737MAC: 0be7cd4beaf9ec2a063170aab65fa5aaCiphertext: 5abc40d7370be7cd4beaf9ec2a063170aab65fa5aa 🔑 密钥的派生

在实际应用中,不应从始至终都使用同一个密钥,更不能直接使用密码(通常是简短的字符串)作为密钥,否则很容易遭受「字典攻击」。应当为每次会话专门准备一个子密钥。这就需要一种能够产生大量子密钥的机制。

KDF

KDF 是 Key Derivation Function 的缩写,即密钥派生函数。能够满足上述需求。这类函数通过引入随机数、增加散列迭代次数,增加暴力破解难度。常用的 KDF 有:

PBKDF2 Scrypt Argon2

Argon2 是最新的算法,也是 Libsodium 首推及其底层默认使用的算法。

基于密码派生密钥

根据给定的密码和一个长度固定的随机数生成指定长度的密钥。

1234567int crypto_pwhash(unsigned char * const out, unsigned long long outlen, const char * const passwd, unsigned long long passwdlen, const unsigned char * const salt, unsigned long long opslimit, size_t memlimit, int alg);

函数 crypto_pwhash() 根据 passwdlen 字节的密码 passwd 和 crypto_pwhash_SALTBYTES 字节的随机数 salt 派生出 outlen 字节的密钥并储存到 out 中。全部参数相同时,生成相同的密钥。

\ passwdlen outlen 最小值 crypto_pwhash_PASSWD_MIN crypto_pwhash_BYTES_MIN 最大值 crypto_pwhash_PASSWD_MAX crypto_pwhash_BYTES_MAX

倒数两个参数 opslimit 和 memlimit 与性能和内存占用有关,取值如下:

\ opslimit memlimit 最小值 crypto_pwhash_OPSLIMIT_MIN crypto_pwhash_MEMLIMIT_MIN 较快/小 crypto_pwhash_OPSLIMIT_INTERACTIVE crypto_pwhash_MEMLIMIT_INTERACTIVE 中等 crypto_pwhash_OPSLIMIT_MODERATE crypto_pwhash_MEMLIMIT_MODERATE 较慢/大 crypto_pwhash_OPSLIMIT_SENSITIVE crypto_pwhash_MEMLIMIT_SENSITIVE 最大值 crypto_pwhash_OPSLIMIT_MAX crypto_pwhash_MEMLIMIT_MAX

最后一个参数 alg 决定选用的算法,只有下列 3 种取值可选:

crypto_pwhash_ALG_DEFAULT Libsodium 推荐的选项。 crypto_pwhash_ALG_ARGON2I13 Argon2i 1.3。 crypto_pwhash_ALG_ARGON2ID13 Argon2id 1.3。

函数返回 0 表示成功;返回 -1 表示失败(这通常是由于操作系统拒绝分配请求的内存)。

1234567891011121314151617181920212223242526#include int main(void){ if (sodium_init() == -1) { return 1; } // 密码 unsigned char passwd[] = "secret"; // 长度固定的随机数 unsigned char salt[crypto_pwhash_SALTBYTES] = {0}; // 密钥 unsigned char key[16]; crypto_pwhash(key, sizeof key, passwd, strlen(passwd), salt, crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT); char buf[1024]; sodium_bin2hex(buf, sizeof buf, key, sizeof key); printf("key: %s\n", buf); return 0;} 1key: a5c2d5ca23026834f7ff177fb8137b62 基于主密钥派生子密钥

根据一个主密钥生成多个子密钥。Libsodium 专门为此提供了两个函数 crypto_kdf_*()。

这两个函数可以根据一个主密钥 key 和一个被称为上下文的参数 ctx 派生出 2^64 个密钥,并且单个子密钥的长度可以在 128(16 字节)到 512 位(64 字节)之间。

1void crypto_kdf_keygen(uint8_t key[crypto_kdf_KEYBYTES]);

函数 crypto_kdf_keygen() 的作用是生成一个主密钥。

1234int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len, uint64_t subkey_id, const char ctx[crypto_kdf_CONTEXTBYTES], const unsigned char key[crypto_kdf_KEYBYTES]);

函数 crypto_kdf_derive_from_key() 可以根据主密钥 key 和上下文 ctx 派生出长度为 subkey_len 字节的子密钥。subkey_id 是子密钥的编号,可以是不大于 2^64 - 1 的任意值。

主密钥的长度必须是 crypto_kdf_KEYBYTES。子密钥的长度 subkey_len 必须介于 crypto_kdf_BYTES_MIN(含)和 crypto_kdf_BYTES_MAX(含)之间。

上下文 ctx 是一个 8 字符的字符串,应能描述子密钥的用途。不需要保密,并且强度可以很低。比如 "UserName"、"__auth__"、"pictures" 和 "userdata" 等。但其长度必须是 crypto_kdf_CONTEXTBYTES 字节。

使用相同的密钥,但使用不同的 ctx,就会得到不同的输出。正如其名,ctx 可以和程序的上下文对应。当然,就算一个程序从头到尾只使用一个 ctx,那也有防止密钥被不同程序重复使用的作用。

123456789101112131415161718192021222324252627282930313233343536#include int main(void){ if (sodium_init() == -1) { return 1; } char ctx[] = "Examples"; uint8_t master_key[crypto_kdf_KEYBYTES]; uint8_t subkey1[16]; uint8_t subkey2[16]; uint8_t subkey3[32]; // 创建主密钥 crypto_kdf_keygen(master_key); // 派生子密钥 crypto_kdf_derive_from_key(subkey1, sizeof subkey1, 1, ctx, master_key); crypto_kdf_derive_from_key(subkey2, sizeof subkey2, 2, ctx, master_key); crypto_kdf_derive_from_key(subkey3, sizeof subkey3, 3, ctx, master_key); // 获取子密钥的十六进制表示 char buf[1024]; sodium_bin2hex(buf, sizeof buf, subkey1, sizeof subkey1); printf("subkey1: %s\n", buf); sodium_bin2hex(buf, sizeof buf, subkey2, sizeof subkey2); printf("subkey2: %s\n", buf); sodium_bin2hex(buf, sizeof buf, subkey3, sizeof subkey3); printf("subkey3: %s\n", buf); return 0;} 123subkey1: 0440b65332dc5f6b4a46d262996af08esubkey2: 73e6d9bbfb25c25d3898ba435f16b710subkey3: 9fdffff7fd9d4ba7a8b1172c79cdf86b7a823256b418e9a61cb8e21f1170ef1f 🔩 辅助函数

尽可能使用这些函数,以抵御「时序攻击」。

测试字节序列sodium_memcmp()

函数 sodium_memcmp() 可完成两个等长字节序列的对比。

1int sodium_memcmp(const void * const b1_, const void * const b2_, size_t len);

如果位于 b1_ 的 len 个字节和位于 b2_ 的 len 个字节相同,函数返回 0,否则返回 -1。

123456789101112131415char b1_[6] = "hello";char b2_[6] = "hello";char b3_[6] = "Hello";if (sodium_memcmp(b1_, b2_, 5) == -1) { puts("Not match");} else { puts("Match");}if (sodium_memcmp(b1_, b3_, 5) == -1) { puts("Not match");} else { puts("Match");} 12MatchNo match sodium_is_zero()

函数 sodium_is_zero() 可判断给定的字节序列是否全为 0。

1int sodium_is_zero(const unsigned char *n, const size_t nlen);

若位于 n 的 nlen 个字节全为 0,则返回 1,否则返回 0。

字节序列的十六进制表示sodium_bin2hex()

函数 sodium_bin2hex() 可获取字节序列的十六进制表示,并由此得到一个字符串。

12char *sodium_bin2hex(char * const hex, const size_t hex_maxlen, const unsigned char * const bin, const size_t bin_len);

函数将字符串写到 hex,这个字符串就是从 bin 开始的 bin_len 个字节的十六进制表示,包括 '\0',故 hex_maxlen 至少为 2*bin_len + 1。该函数始终返回 hex。

12345char hex[9]; // 2*4 + 1 = 9char bin[5] = "AAAA";sodium_bin2hex(hex, 9, bin, 4);puts(hex); 141414141 sodium_hex2bin()

函数 sodium_hex2bin() 作用相反,通过解析字节序列的十六进制表示,还原该字节序列。

1234int sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, const char * const hex, const size_t hex_len, const char * const ignore, size_t * const bin_len, const char ** const hex_end);

函数将字节序列写到 bin。bin_maxlen 表示允许写入的最大字节数。而位于 hex 的字符串应当是一个字节序列的十六进制表示,可以没有 '\0' 结尾,需要解析的长度由 hex_len 指定。

ignore 是需要跳过的字符组成的字符串。比如 ": " 表示跳过冒号和空格。此时 "69:FC"、"69 FC"、"69 : FC" 和 "69FC" 都视为合法的输入,并产生相同的输出。ignore 可以设为 NULL,表示不允许任何非法的字符出现。

函数返回 0 表示转换成功,同时 bin_len 会被设为解析得到的字节数;返回 -1 则表示失败。失败的情况有以下两种:

解析的结果超过 bin_maxlen 字节; 遇到非法字符时,如果前面的字符都能顺利解析,函数仍然返回 0,否则返回 -1。

无论如何 hex_end 总是会被设为下一个待解析的字符的地址。

1234567char bin[5] = {0};char hex[12] = "61*62636472";size_t bin_len = 0;const char * hex_end;sodium_hex2bin(bin, 4, hex, 9, "*", &bin_len, &hex_end);printf("%d: %s, %c\n", bin_len, bin, *hex_end); 14: abcd, 7 Base64 编码/解码sodium_bin2base64()

函数 sodium_bin2base64() 可获取字节序列的 Base64 编码。

123char *sodium_bin2base64(char * const b64, const size_t b64_maxlen, const unsigned char * const bin, const size_t bin_len, const int variant);

Base64 编码有多种变体,采用哪种变体由 variant 指定,有下列 4 种取值可选:

sodium_base64_VARIANT_ORIGINAL sodium_base64_VARIANT_ORIGINAL_NO_PADDING sodium_base64_VARIANT_URLSAFE sodium_base64_VARIANT_URLSAFE_NO_PADDING

这些 Base64 编码并不提供任何形式的加密;就像十六进制编码一样,任何人都可以对它们进行解码。

可以令 b64_maxlen 等于宏 sodium_base64_ENCODED_LEN(BIN_LEN, VARIANT),它表示使用 VARIANT 这种变体时,BIN_LEN 个字节的 Base64 编码(包括 '\0')的最小长度。

123456char bin[6] = "hello";int b64_len = sodium_base64_ENCODED_LEN(5, sodium_base64_VARIANT_ORIGINAL);char b64[b64_len];sodium_bin2base64(b64, b64_len, bin, 5, sodium_base64_VARIANT_ORIGINAL);printf("%d: %s\n", b64_len, b64); 19: aGVsbG8= sodium_base642bin()

函数 sodium_base642bin() 可完成 Base64 解码工作。

1234int sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen, const char * const b64, const size_t b64_len, const char * const ignore, size_t * const bin_len, const char ** const b64_end, const int variant);

返回 -1 表示错误,返回 0 表示解码成功,同时 bin_len 会被设为解码得到的字节数,其他参数的含义参考前文。

1234567size_t bin_len;char bin[6];char b64[9] = "aGVsbG8=";sodium_base642bin(bin, sizeof bin, b64, strlen(b64), "", &bin_len, NULL, sodium_base64_VARIANT_ORIGINAL);printf("%d: %s\n", bin_len, bin); 15: hello 大数的计算sodium_increment()

函数 sodium_increment() 用来递增一个任意长度的无符号数。

1void sodium_increment(unsigned char *n, const size_t nlen);

位于 n 的 nlen 字节的数字将按小端字节序处理。加密算法中经常提到的不重数 nonce 就可用此函数进行递增。

12345678910unsigned char nonce[8] = {0};sodium_increment(nonce, sizeof(nonce));printf("%d\n", *(int *)nonce);sodium_increment(nonce, sizeof(nonce));printf("%d\n", *(int *)nonce);sodium_increment(nonce, sizeof(nonce));printf("%d\n", *(int *)nonce); 123123 sodium_add()

函数 sodium_add() 可完成大数的加法。

1void sodium_add(unsigned char *a, const unsigned char *b, const size_t len);

位于 a 和 b 的两个 nlen 字节的加数均按小端字节序的无符号数处理。计算结果将覆盖 a。

123456unsigned char a[8] = {1};unsigned char b[8] = {1};printf("%d\n", *(int *)a);sodium_add(a, b, sizeof a); // a = a + bprintf("%d\n", *(int *)a); 1212 sodium_sub()

函数 sodium_sub() 可完成大数减法。

1void sodium_sub(unsigned char *a, const unsigned char *b, const size_t len);

位于 a 和 b 的两个 nlen 字节的加数均按小端字节序的无符号数处理。计算结果将覆盖 a。

sodium_compare()

函数 sodium_compare() 可完成两个大数的比较。两个大数均按小端字节序处理。

1int sodium_compare(const void * const b1_, const void * const b2_, size_t len);

返回 0 表示相等,返回 -1 表示 b1_ 小于 b2_;返回 1 表示 b1_ 大于 b2_。

🔗 参考文献 libsodium 密码学库 中文文档 现代密码学实践指南[2015年] 【翻译】密码学一小时必知 加密解密学习笔记 密码学基础系列 实用密码学工具——KDF 如何存储密码(KDF) ldconfig命令 pkg-config 详解 什么是 AES-NI(AES指令集)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3