Linux内核AES加密算法用法

在 Linux 内核中使用 AES 加密算法主要通过 内核加密 API 实现。这个 API 提供了一个抽象层,允许内核模块(如文件系统加密 dm-crypt/LUKS、IPSec、磁盘加密等)使用各种加密算法,包括 AES,而无需关心底层具体的实现(是软件实现还是硬件加速)。

以下是使用内核 AES 加密的基本步骤和要点:

核心组件:

  1. struct crypto_skcipher: 这是表示对称密钥加密(如 AES)上下文的句柄。它封装了算法、密钥、操作模式(如 CBC, XTS, CTR, GCM 等)等信息。
  2. struct skcipher_request: 这是用于封装单次加密或解密操作请求的结构。它包含输入/输出数据的散列表(struct scatterlist)、初始化向量(IV)、异步操作完成后的回调函数等信息。
  3. struct scatterlist: 用于描述分散/聚集 I/O 的数据缓冲区。内核加密 API 通常操作的是 scatterlist 而不是直接的线性内存地址,以高效处理可能分散在物理内存中的数据。

基本使用流程:

  1. 分配算法句柄 (crypto_alloc_skcipher)

    1
    2
    struct crypto_skcipher *tfm;
    tfm = crypto_alloc_skcipher("aes-<mode>-<keylength>", 0, 0);
    • "aes-<mode>-<keylength>": 指定算法名称字符串。常见组合:
      • "ecb(aes)": AES ECB 模式 (通常不推荐用于安全加密)。
      • "cbc(aes)": AES CBC 模式。
      • "ctr(aes)": AES CTR 模式。
      • "xts(aes)": AES XTS 模式 (常用于磁盘加密)。
      • "gcm(aes)": AES GCM 模式 (带认证的加密)。
      • "pcbc(aes)", "lrw(aes)", "ofb(aes)", "cfb(aes)" 等。
      • 密钥长度:通常在模式名后隐含指定(如 cbc(aes) 需要调用 setkey 时指定长度),但有些名字明确包含长度(如 "aes-xts-plain64" 常用于 dm-crypt,但实际密钥长度由 setkey 决定)。最重要的是 setkey 调用时传递的密钥长度必须与所选算法变体期望的长度一致(128, 192, 256 位)。
    • 0, 0: 通常表示使用默认实现(优先硬件加速)。可以指定 CRYPTO_ALG_ASYNC 标志启用异步操作(利用硬件加速时常用)。
  2. 设置密钥 (crypto_skcipher_setkey)

    1
    2
    3
    4
    5
    6
    7
    int err;
    const u8 *key = ...; // 指向你的密钥数据的指针
    unsigned int keylen = ...; // 密钥长度(字节数):16 (128-bit), 24 (192-bit), 32 (256-bit)
    err = crypto_skcipher_setkey(tfm, key, keylen);
    if (err) {
    // 处理错误:无效密钥长度或不支持等
    }
    • 关键点keylen 必须 与你选择的算法变体(在 crypto_alloc_skcipher 时指定)所要求的长度完全匹配。否则会返回 -EINVAL
  3. 准备请求 (skcipher_request_alloc + 初始化)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    struct skcipher_request *req;
    struct scatterlist sg_in, sg_out;
    DECLARE_CRYPTO_WAIT(wait); // 用于同步等待的辅助结构
    req = skcipher_request_alloc(tfm, GFP_KERNEL);
    if (!req) {
    // 处理内存分配失败
    }
    // 初始化输入和输出的 scatterlist (假设源数据在 src, 目标在 dst, 长度 len)
    sg_init_one(&sg_in, src, len);
    sg_init_one(&sg_out, dst, len);
    // 将请求关联到 tfm
    skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
    CRYPTO_TFM_REQ_MAY_SLEEP,
    crypto_req_done, &wait);
    skcipher_request_set_crypt(req, &sg_in, &sg_out, len, iv);
    • skcipher_request_alloc: 分配一个请求结构并将其与 tfm 关联。
    • sg_init_one: 初始化一个 scatterlist 表示单个线性缓冲区(srcdst 是内核虚拟地址)。如果数据分散,使用 sg_init_table 等更复杂的操作。
    • skcipher_request_set_callback: 设置异步操作完成后的回调函数 (crypto_req_done) 和一个上下文 (&wait)。CRYPTO_TFM_REQ_MAY_BACKLOG 允许请求在硬件队列满时排队,CRYPTO_TFM_REQ_MAY_SLEEP 允许在内存分配时休眠。
    • skcipher_request_set_crypt: 这是核心配置函数:
      • req: 请求指针。
      • &sg_in: 输入数据(明文或密文)的散列表头指针。
      • &sg_out: 输出数据(密文或明文)的散列表头指针。
      • len: 要处理的数据长度(字节)。
      • iv: 指向初始化向量 (IV) 缓冲区的指针。IV 的长度和生成方式取决于所选的操作模式(如 CBC 需要 16 字节 IV)。
  4. 执行操作 (加密/解密)

    • 加密:
      1
      2
      3
      4
      5
      6
      7
      8
      err = crypto_skcipher_encrypt(req);
      if (err == -EINPROGRESS || err == -EBUSY) {
      // 对于异步操作,等待完成
      err = crypto_wait_req(err, &wait);
      }
      if (err) {
      // 处理加密错误
      }
    • 解密:
      1
      2
      3
      4
      5
      6
      7
      err = crypto_skcipher_decrypt(req);
      if (err == -EINPROGRESS || err == -EBUSY) {
      err = crypto_wait_req(err, &wait);
      }
      if (err) {
      // 处理解密错误(可能意味着认证失败 -GCM, 或数据损坏/密钥错误)
      }
    • crypto_skcipher_encrypt / crypto_skcipher_decrypt: 提交请求。如果返回 -EINPROGRESS-EBUSY,表示操作是异步的并在后台执行。
    • crypto_wait_req: 一个辅助函数,用于同步等待异步请求完成。它会阻塞当前线程直到操作完成或出错。crypto_req_done 回调会唤醒这个等待。
  5. 清理资源

    1
    2
    skcipher_request_free(req); // 释放请求结构
    crypto_free_skcipher(tfm); // 释放算法句柄
    • 务必释放分配的资源以避免内存泄漏。

重要注意事项:

  1. 模式选择: AES 是一个分组密码。必须选择一个合适的操作模式 (CBC, XTS, CTR, GCM 等) 来加密超过一个块的数据。选择模式取决于安全需求(保密性、认证)、性能、并行化能力和具体应用场景(文件加密、网络协议等)。例如:
    • 全盘加密 (dm-crypt/LUKS): 常用 XTS 模式。
    • IPSec ESP: 常用 CBC 或 GCM 模式。
    • 需要认证: 使用 GCM 或 CCM 等 AEAD 模式(通过 crypto_aead API)。
  2. 密钥管理: 安全地生成、存储和销毁密钥是至关重要的。内核模块通常需要从用户空间(通过 netlink, ioctl 等)或其他安全来源(如 TPM)获取密钥。切勿将密钥硬编码在内核中!
  3. IV 管理: 对于大多数模式(CBC, CTR, XTS 等),IV 必须是唯一的(对于给定的密钥)。重复使用 IV 会严重破坏安全性。IV 通常不需要保密,但 GCM 的 nonce 有其特殊要求。IV 的生成和传递方式由协议或应用规范决定(例如,在文件加密中,IV 可能存储在文件头或由扇区号派生)。
  4. 数据对齐: 虽然现代内核实现通常能处理非对齐访问,但为了最佳性能,输入/输出缓冲区和 IV 缓冲区最好按算法块大小(AES 是 16 字节)对齐。
  5. 异步操作: 当使用硬件加速引擎时,加密/解密操作通常是异步的。使用回调函数和等待机制(如 crypto_wait_req)是处理异步操作的标准方式。
  6. 错误处理: 仔细检查所有函数调用的返回值(crypto_alloc_skcipher, crypto_skcipher_setkey, crypto_skcipher_encrypt/decrypt)。crypto_skcipher_setkey 失败最常见的原因是密钥长度不匹配。
  7. AEAD (Authenticated Encryption with Associated Data): 如果需要同时提供保密性、完整性和认证(如 GCM 模式),应该使用 crypto_aead API 而不是 crypto_skcipher API。它的使用方式类似但增加了关联数据 (AAD) 的设置。

示例片段 (简化概念):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <linux/crypto.h>
#include <crypto/skcipher.h>

void do_aes_cbc_encrypt(const u8 *key, unsigned int keylen,
const u8 *iv, const u8 *plaintext,
u8 *ciphertext, size_t len) {
struct crypto_skcipher *tfm = NULL;
struct skcipher_request *req = NULL;
struct scatterlist sg_in, sg_out;
DECLARE_CRYPTO_WAIT(wait);
int err;

// 1. 分配算法句柄 (CBC 模式)
tfm = crypto_alloc_skcipher("cbc(aes)", 0, 0);
if (IS_ERR(tfm)) {
err = PTR_ERR(tfm);
goto out;
}

// 2. 设置密钥
err = crypto_skcipher_setkey(tfm, key, keylen);
if (err) goto out_free_tfm;

// 3. 分配并初始化请求
req = skcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {
err = -ENOMEM;
goto out_free_tfm;
}
sg_init_one(&sg_in, plaintext, len);
sg_init_one(&sg_out, ciphertext, len);
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);
skcipher_request_set_crypt(req, &sg_in, &sg_out, len, iv);

// 4. 执行加密 (同步等待)
err = crypto_skcipher_encrypt(req);
if (err == -EINPROGRESS || err == -EBUSY) {
err = crypto_wait_req(err, &wait);
}
if (err) goto out_free_req;

out_free_req:
skcipher_request_free(req);
out_free_tfm:
crypto_free_skcipher(tfm);
out:
if (err) pr_err("AES CBC encryption failed: %d\n", err);
}

总结:

在内核中使用 AES 加密涉及使用 crypto_skcipher API(或 crypto_aead 用于认证加密)。关键步骤包括:选择合适的算法/模式字符串分配句柄 (crypto_alloc_skcipher)、正确设置密钥 (crypto_skcipher_setkey)、使用 scatterlist 准备输入/输出数据、分配并配置请求 (skcipher_request_alloc, skcipher_request_set_crypt)、设置 IV、执行操作 (crypto_skcipher_encrypt/decrypt) 并处理可能的异步等待、最后释放资源。务必谨慎处理密钥、IV 和错误代码。实际应用应参考内核源码树中的示例(如 drivers/crypto/, crypto/tcrypt.c, dm-crypt 驱动等)。

给一个示例

以下是一个完整的 Linux 内核模块示例,演示如何使用 AES-CBC 算法进行加密和解密操作。该模块在加载时执行加密和解密,并通过内核日志输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <linux/module.h>
#include <linux/crypto.h>
#include <crypto/skcipher.h>
#include <linux/scatterlist.h>
#include <linux/string.h>

#define AES_KEY_SIZE 16 // 128-bit AES
#define AES_BLOCK_SIZE 16 // AES 块大小
#define DATA_SIZE 64 // 测试数据大小(必须是块大小的倍数)

static struct crypto_skcipher *tfm;
static u8 key[AES_KEY_SIZE];
static u8 iv[AES_BLOCK_SIZE];
static u8 plaintext[DATA_SIZE];
static u8 ciphertext[DATA_SIZE];
static u8 decrypted[DATA_SIZE];

// 执行 AES 加密/解密操作
static int test_aes_operation(int encrypt)
{
struct skcipher_request *req;
struct scatterlist sg_in, sg_out;
DECLARE_CRYPTO_WAIT(wait);
int err;

// 分配请求对象
req = skcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {
pr_err("Failed to allocate skcipher request\n");
return -ENOMEM;
}

// 设置输入输出散列表
sg_init_one(&sg_in, encrypt ? plaintext : ciphertext, DATA_SIZE);
sg_init_one(&sg_out, encrypt ? ciphertext : decrypted, DATA_SIZE);

// 设置请求回调
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);

// 设置加密参数(使用相同的 IV)
skcipher_request_set_crypt(req, &sg_in, &sg_out, DATA_SIZE, iv);

// 执行加密或解密
if (encrypt)
err = crypto_skcipher_encrypt(req);
else
err = crypto_skcipher_decrypt(req);

// 处理异步操作
if (err == -EINPROGRESS || err == -EBUSY) {
err = crypto_wait_req(err, &wait);
}

skcipher_request_free(req);
return err;
}

// 打印数据(调试用)
static void print_data(const char *label, const u8 *data, size_t size)
{
char *buf;
int i;

buf = kzalloc(size * 3 + 1, GFP_KERNEL); // 每个字节2字符+空格+null
if (!buf) return;

for (i = 0; i < size; i++)
sprintf(buf + i * 3, "%02x ", data[i]);

pr_info("%s: %s\n", label, buf);
kfree(buf);
}

static int __init aes_example_init(void)
{
int err;

pr_info("AES Example Module Loaded\n");

// 1. 初始化测试数据
memset(key, 0xAA, AES_KEY_SIZE); // 简单测试密钥
memset(iv, 0x55, AES_BLOCK_SIZE); // 初始化向量
memset(plaintext, 0x41, DATA_SIZE); // 填充 'A'
plaintext[DATA_SIZE - 1] = 0; // 空终止符(仅用于打印)

print_data("Key ", key, AES_KEY_SIZE);
print_data("IV ", iv, AES_BLOCK_SIZE);
print_data("Plaintext", plaintext, min_t(size_t, 32, DATA_SIZE));

// 2. 分配加密上下文
tfm = crypto_alloc_skcipher("cbc(aes)", 0, 0);
if (IS_ERR(tfm)) {
pr_err("Error allocating AES-CBC transform: %ld\n", PTR_ERR(tfm));
return PTR_ERR(tfm);
}

// 3. 设置密钥
err = crypto_skcipher_setkey(tfm, key, AES_KEY_SIZE);
if (err) {
pr_err("Error setting key: %d\n", err);
goto free_tfm;
}

// 4. 执行加密
err = test_aes_operation(1);
if (err) {
pr_err("Encryption failed: %d\n", err);
goto free_tfm;
}
print_data("Ciphertext", ciphertext, min_t(size_t, 32, DATA_SIZE));

// 5. 执行解密
err = test_aes_operation(0);
if (err) {
pr_err("Decryption failed: %d\n", err);
goto free_tfm;
}
print_data("Decrypted", decrypted, min_t(size_t, 32, DATA_SIZE));

// 6. 验证结果
if (memcmp(plaintext, decrypted, DATA_SIZE) {
pr_err("Decryption result doesn't match original!\n");
err = -EINVAL;
} else {
pr_info("Success! Decrypted text matches original\n");
}

free_tfm:
crypto_free_skcipher(tfm);
return err;
}

static void __exit aes_example_exit(void)
{
pr_info("AES Example Module Unloaded\n");
}

module_init(aes_example_init);
module_exit(aes_example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Linux Kernel AES Encryption Example");

使用说明:

  1. 编译模块
    保存为 aes_example.c,使用以下 Makefile:

    1
    2
    3
    4
    5
    obj-m += aes_example.o
    all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  2. 加载模块

    1
    sudo insmod aes_example.ko
  3. 查看结果

    1
    dmesg | tail -n 30

预期输出:

1
2
3
4
5
6
Key     : aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa 
IV : 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55
Plaintext: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 ...
Ciphertext: 1d 8c 46 46 0c 1c 40 4b fb 87 0f 3d 7d 3b 1d 8c ... (随机)
Decrypted: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 ...
Success! Decrypted text matches original

关键点说明:

  1. 算法选择:使用 "cbc(aes)" 指定 AES-CBC 模式
  2. 密钥管理
    • 128-bit 密钥 (16字节)
    • 通过 crypto_skcipher_setkey() 设置
  3. IV 处理
    • 固定大小 (16字节)
    • 每次操作前重置(实际应用中必须唯一)
  4. 数据准备
    • 使用 scatterlist 处理缓冲区
    • 数据长度必须是块大小(16字节)的倍数
  5. 异步操作
    • 使用 crypto_wait_req() 处理异步完成
  6. 资源管理
    • 正确释放请求和算法上下文
    • 错误检查所有步骤

实际应用注意事项:

  1. 密钥安全:不要硬编码密钥,应从安全来源获取
  2. IV 生成:使用随机 IV(如 get_random_bytes()),保证唯一性
  3. 数据填充:非对齐数据需要添加填充(如 PKCS#7)
  4. 性能优化:对于大数据,使用多个 scatterlist 条目
  5. 认证模式:如需完整性保护,改用 crypto_aead API (GCM/CCM)

此示例演示了内核中 AES 加密的基本流程,实际使用时需根据具体场景调整安全参数和数据处理逻辑。

Linux内核crypto_cipher_encrypt_one接口用法及示例

Linux 内核 crypto_cipher_encrypt_one 接口用法及示例

crypto_cipher_encrypt_one 是 Linux 内核中用于单块加密的低级 API,它提供了一种简单直接的方式来执行块加密算法的单次加密操作。这个接口通常用于 ECB(电子密码本)模式,或作为构建更复杂加密模式的基础。

接口特点

  1. 简单性:直接的单块加密操作
  2. 同步操作:立即返回结果,无需异步处理
  3. 底层接口:适合构建更高级的加密模式或特定硬件操作
  4. 单块处理:每次只处理一个加密块(如 AES 的 16 字节)

函数原型

1
2
void crypto_cipher_encrypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src);
void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, u8 *dst, const u8 *src);

使用步骤

  1. 分配密码对象crypto_alloc_cipher()
  2. 设置密钥crypto_cipher_setkey()
  3. 执行加密/解密crypto_cipher_encrypt_one()/crypto_cipher_decrypt_one()
  4. 释放密码对象crypto_free_cipher()

完整示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/string.h>

#define AES_KEY_SIZE 16 // 128-bit AES
#define AES_BLOCK_SIZE 16 // AES 块大小

static struct crypto_cipher *tfm;
static u8 key[AES_KEY_SIZE];
static u8 plaintext[AES_BLOCK_SIZE];
static u8 ciphertext[AES_BLOCK_SIZE];
static u8 decrypted[AES_BLOCK_SIZE];

// 打印数据(调试用)
static void print_data(const char *label, const u8 *data, size_t size)
{
char buf[64]; // 用于存储十六进制表示
char *pos = buf;
int i;

for (i = 0; i < min_t(size_t, size, 16); i++) {
pos += sprintf(pos, "%02x ", data[i]);
}

if (size > 16) {
sprintf(pos, "...");
}

pr_info("%s: %s\n", label, buf);
}

static int __init cipher_example_init(void)
{
int err;

pr_info("Crypto Cipher Example Module Loaded\n");

// 1. 初始化测试数据
memset(key, 0xAA, AES_KEY_SIZE); // 简单测试密钥
memset(plaintext, 0x41, AES_BLOCK_SIZE); // 填充 'A'

print_data("Key ", key, AES_KEY_SIZE);
print_data("Plaintext", plaintext, AES_BLOCK_SIZE);

// 2. 分配密码对象
tfm = crypto_alloc_cipher("aes", 0, 0);
if (IS_ERR(tfm)) {
pr_err("Error allocating AES cipher: %ld\n", PTR_ERR(tfm));
return PTR_ERR(tfm);
}

// 3. 设置密钥
err = crypto_cipher_setkey(tfm, key, AES_KEY_SIZE);
if (err) {
pr_err("Error setting key: %d\n", err);
goto free_tfm;
}

// 4. 执行加密
crypto_cipher_encrypt_one(tfm, ciphertext, plaintext);
print_data("Ciphertext", ciphertext, AES_BLOCK_SIZE);

// 5. 执行解密
crypto_cipher_decrypt_one(tfm, decrypted, ciphertext);
print_data("Decrypted ", decrypted, AES_BLOCK_SIZE);

// 6. 验证结果
if (memcmp(plaintext, decrypted, AES_BLOCK_SIZE)) {
pr_err("Decryption result doesn't match original!\n");
err = -EINVAL;
} else {
pr_info("Success! Decrypted text matches original\n");
}

free_tfm:
crypto_free_cipher(tfm);
return err;
}

static void __exit cipher_example_exit(void)
{
pr_info("Crypto Cipher Example Module Unloaded\n");
}

module_init(cipher_example_init);
module_exit(cipher_example_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Linux Kernel crypto_cipher Example");

编译和使用

  1. 保存文件:将代码保存为 cipher_example.c

  2. 创建 Makefile

    1
    2
    3
    4
    5
    obj-m += cipher_example.o
    all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
    clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
  3. 编译模块

    1
    make
  4. 加载模块

    1
    sudo insmod cipher_example.ko
  5. 查看结果

    1
    dmesg | tail -n 20

预期输出

1
2
3
4
5
Key      : aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa 
Plaintext: 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
Ciphertext: 7e 87 6f 3c 0d c3 4d 5d 7d e2 6b 3d 26 5d 0c 3f
Decrypted : 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
Success! Decrypted text matches original

关键点说明

  1. 算法名称

    • 使用 "aes" 而不是 "cbc(aes)""ecb(aes)"
    • crypto_cipher API 默认使用 ECB 模式
  2. 单块操作

    • 每次只处理一个加密块(AES 为 16 字节)
    • 不适合直接处理大数据流
  3. 同步操作

    • 函数立即执行并返回
    • 不需要异步处理或回调机制
  4. 密钥设置

    • 密钥长度必须与算法要求一致
    • AES 支持 16 (128-bit), 24 (192-bit), 32 (256-bit) 字节密钥

实际应用场景

  1. 硬件加速实现:在自定义硬件加密驱动中作为基础操作
  2. 构建加密原语:用于实现更高级的加密模式
  3. 密码学实验:测试和验证加密算法的基本功能
  4. 密钥派生操作:在某些密钥派生函数中使用

安全注意事项

  1. ECB 模式限制

    • ECB 模式不提供语义安全性
    • 相同明文块总是产生相同密文块
    • 不适合直接用于加密敏感数据
  2. 仅限单块操作

    • 对于多块数据,需要实现链式操作(如 CBC、CTR)
    • 实际应用中应使用更高级的 API(如 crypto_skcipher
  3. 密钥管理

    • 示例中硬编码密钥仅用于演示
    • 实际应用中应从安全来源获取密钥

crypto_skcipher 的区别

特性 crypto_cipher crypto_skcipher
操作模式 基本 ECB 模式 支持多种模式 (CBC, CTR, XTS 等)
数据处理 单块 (16 字节) 任意长度数据
操作类型 同步 支持异步操作
IV 支持 不支持 支持
使用场景 底层操作、硬件驱动 通用加密需求
性能 更轻量级 功能更全面但稍重

何时使用 crypto_cipher

  1. 实现自定义加密模式或协议
  2. 编写硬件加密驱动程序
  3. 需要直接访问底层块加密操作
  4. 性能敏感且只需 ECB 模式的场景

对于大多数内核加密需求,推荐使用更高级的 crypto_skcipher API,它提供了更完整的加密解决方案和更好的安全性。