keyctl - 密钥管理控制接口

keyctl - 密钥管理控制接口

1. 函数介绍

keyctl 是一个 Linux 系统调用,用于管理和操作内核密钥保留服务(Key Retention Service)。它提供了对内核密钥管理子系统的完整控制接口,允许进程创建、检索、更新和删除各种类型的密钥。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

密钥保留服务是 Linux 内核的安全基础设施组件,用于安全地存储和管理密钥、密码、证书等敏感信息。

2. 函数原型

1
2
3
4
5
#include <sys/types.h>
#include <keyutils.h>

long keyctl(int cmd, ...);

注意:这不是标准 C 库函数,需要通过 syscall() 调用或使用 libkeyutils 库。

3. 功能

执行各种密钥管理操作,包括:

  • 创建和删除密钥

  • 设置和获取密钥属性

  • 链接和取消链接密钥

  • 搜索和查找密钥

  • 设置密钥权限

  • 管理密钥环

4. 常用命令参数

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
// 密钥管理命令
#define KEYCTL_GET_KEYRING_ID 0 /* 获取密钥环 ID */
#define KEYCTL_JOIN_SESSION_KEYRING 1 /* 加入会话密钥环 */
#define KEYCTL_UPDATE 2 /* 更新密钥 */
#define KEYCTL_REVOKE 3 /* 撤销密钥 */
#define KEYCTL_CHOWN 4 /* 更改密钥所有者 */
#define KEYCTL_SETPERM 5 /* 设置密钥权限 */
#define KEYCTL_DESCRIBE 6 /* 描述密钥 */
#define KEYCTL_CLEAR 7 /* 清空密钥环 */
#define KEYCTL_LINK 8 /* 链接密钥 */
#define KEYCTL_UNLINK 9 /* 取消链接密钥 */
#define KEYCTL_SEARCH 10 /* 搜索密钥 */
#define KEYCTL_READ 11 /* 读取密钥 */
#define KEYCTL_INSTANTIATE 12 /* 实例化密钥 */
#define KEYCTL_NEGATE 13 /* 否定密钥 */
#define KEYCTL_SET_REQKEY_KEYRING 14 /* 设置请求密钥环 */
#define KEYCTL_SET_TIMEOUT 15 /* 设置密钥超时 */
#define KEYCTL_ASSUME_AUTHORITY 16 /* 假设权限 */
#define KEYCTL_GET_SECURITY 17 /* 获取安全上下文 */
#define KEYCTL_SESSION_TO_PARENT 18 /* 会话到父进程 */
#define KEYCTL_REJECT 19 /* 拒绝密钥 */
#define KEYCTL_INSTANTIATE_IOV 20 /* 实例化密钥 (iov) */
#define KEYCTL_INVALIDATE 21 /* 使密钥无效 */
#define KEYCTL_GET_PERSISTENT 22 /* 获取持久密钥环 */

5. 密钥类型

1
2
3
4
5
6
7
8
9
// 常见密钥类型
"user" // 用户定义的密钥
"logon" // 登录凭证密钥
"trusted" // 受信任的密钥
"encrypted" // 加密密钥
"dns_resolver" // DNS 解析器密钥
"rxrpc" // RxRPC 密钥
"syzkaller" // 系统调用模糊测试密钥

6. 返回值

  • 成功时:返回值取决于具体命令

  • 失败时:返回 -1,并设置 errno

7. 常见 errno 错误码

  • ENOKEY: 密钥不存在

  • EKEYEXPIRED: 密钥已过期

  • EKEYREVOKED: 密钥已被撤销

  • EACCES: 权限不足

  • EPERM: 操作被拒绝

  • EINVAL: 参数无效

  • ENOMEM: 内存不足

  • EDQUOT: 配额超限

  • EOPNOTSUPP: 操作不支持

8. 相似函数,或关联函数

  • add_key(): 添加新密钥

  • request_key(): 请求密钥

  • keyctl() 系列函数

  • /sbin/keyctl: 用户态密钥管理工具

  • /proc/keys: 查看系统密钥信息

  • /proc/key-users: 查看密钥用户信息

9. 示例代码

示例1:基本使用 - 密钥创建和管理

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
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <keyutils.h>
#include <errno.h>
#include <string.h>

#ifndef SYS_keyctl
# define SYS_keyctl 250 // x86_64 架构下的系统调用号
#endif

// keyctl 系统调用包装函数
long keyctl_wrapper(int cmd, ...) {
va_list args;
va_start(args, cmd);
long result = syscall(SYS_keyctl, cmd, va_arg(args, long),
va_arg(args, long), va_arg(args, long),
va_arg(args, long));
va_end(args);
return result;
}

int main() {
printf("=== keyctl 基本使用演示 ===\n");

// 检查密钥支持
key_serial_t session_keyring = keyctl(KEYCTL_GET_KEYRING_ID,
KEY_SPEC_SESSION_KEYRING, 0);
if (session_keyring == -1) {
printf("错误: 系统不支持密钥保留服务: %s\n", strerror(errno));
return 1;
}

printf("✓ 密钥保留服务可用\n");
printf("会话密钥环 ID: %d\n", session_keyring);

// 创建一个用户密钥
const char *key_desc = "my_test_key";
const char *key_data = "This is my secret data";

key_serial_t key = add_key("user", key_desc, key_data, strlen(key_data),
KEY_SPEC_SESSION_KEYRING);
if (key == -1) {
printf("创建密钥失败: %s\n", strerror(errno));
return 1;
}

printf("✓ 成功创建密钥,ID: %d\n", key);

// 描述密钥
char description&#91;256];
long desc_len = keyctl(KEYCTL_DESCRIBE, key, (long)description,
sizeof(description), 0);
if (desc_len != -1) {
description&#91;desc_len] = '\0';
printf("密钥描述: %s\n", description);
}

// 读取密钥数据
char read_data&#91;256];
long data_len = keyctl(KEYCTL_READ, key, (long)read_data,
sizeof(read_data), 0);
if (data_len != -1) {
read_data&#91;data_len] = '\0';
printf("密钥数据: %s\n", read_data);
}

// 设置密钥超时(30秒后过期)
if (keyctl(KEYCTL_SET_TIMEOUT, key, 30, 0, 0) == 0) {
printf("✓ 设置密钥超时为 30 秒\n");
}

// 获取密钥安全上下文
char security_context&#91;256];
long sec_len = keyctl(KEYCTL_GET_SECURITY, key,
(long)security_context, sizeof(security_context), 0);
if (sec_len != -1) {
security_context&#91;sec_len] = '\0';
printf("安全上下文: %s\n", security_context);
}

// 撤销密钥
if (keyctl(KEYCTL_REVOKE, key, 0, 0, 0) == 0) {
printf("✓ 成功撤销密钥\n");
}

return 0;
}

示例2:密钥环操作

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
146
147
148
149
150
151
152
153
154
155
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <keyutils.h>
#include <errno.h>
#include <string.h>

void demonstrate_keyring_operations() {
printf("=== 密钥环操作演示 ===\n");

// 获取各种密钥环 ID
key_serial_t session_ring = keyctl(KEYCTL_GET_KEYRING_ID,
KEY_SPEC_SESSION_KEYRING, 0);
key_serial_t process_ring = keyctl(KEYCTL_GET_KEYRING_ID,
KEY_SPEC_PROCESS_KEYRING, 0);
key_serial_t thread_ring = keyctl(KEYCTL_GET_KEYRING_ID,
KEY_SPEC_THREAD_KEYRING, 0);

printf("密钥环 ID:\n");
printf(" 会话密钥环: %d\n", session_ring);
printf(" 进程密钥环: %d\n", process_ring);
printf(" 线程密钥环: %d\n", thread_ring);

// 创建自定义密钥环
key_serial_t custom_ring = add_key("keyring", "my_custom_ring",
NULL, 0, KEY_SPEC_SESSION_KEYRING);
if (custom_ring != -1) {
printf("✓ 创建自定义密钥环: %d\n", custom_ring);

// 在自定义密钥环中创建密钥
key_serial_t ring_key = add_key("user", "ring_key",
"data in ring", 12, custom_ring);
if (ring_key != -1) {
printf("✓ 在自定义密钥环中创建密钥: %d\n", ring_key);
}

// 清空自定义密钥环
if (keyctl(KEYCTL_CLEAR, custom_ring, 0, 0, 0) == 0) {
printf("✓ 清空自定义密钥环\n");
}

// 撤销自定义密钥环
if (keyctl(KEYCTL_REVOKE, custom_ring, 0, 0, 0) == 0) {
printf("✓ 撤销自定义密钥环\n");
}
}

// 加入新的会话密钥环
key_serial_t new_session = keyctl(KEYCTL_JOIN_SESSION_KEYRING,
(long)"new_session", 0, 0, 0);
if (new_session != -1) {
printf("✓ 加入新的会话密钥环: %d\n", new_session);
}
}

void demonstrate_key_search() {
printf("\n=== 密钥搜索演示 ===\n");

// 创建测试密钥
key_serial_t test_key = add_key("user", "search_test",
"search data", 11,
KEY_SPEC_SESSION_KEYRING);
if (test_key == -1) {
printf("创建测试密钥失败: %s\n", strerror(errno));
return;
}

printf("创建测试密钥: %d\n", test_key);

// 搜索密钥
key_serial_t found_key = keyctl(KEYCTL_SEARCH,
KEY_SPEC_SESSION_KEYRING,
(long)"user", (long)"search_test", 0);
if (found_key != -1) {
printf("✓ 找到密钥: %d\n", found_key);

// 验证找到的密钥
if (found_key == test_key) {
printf("✓ 验证成功:找到的密钥 ID 匹配\n");
}
} else {
printf("搜索密钥失败: %s\n", strerror(errno));
}

// 撤销测试密钥
keyctl(KEYCTL_REVOKE, test_key, 0, 0, 0);
}

void demonstrate_key_permissions() {
printf("\n=== 密钥权限演示 ===\n");

// 创建测试密钥
key_serial_t perm_key = add_key("user", "perm_test",
"permission data", 15,
KEY_SPEC_SESSION_KEYRING);
if (perm_key == -1) {
printf("创建权限测试密钥失败: %s\n", strerror(errno));
return;
}

printf("创建权限测试密钥: %d\n", perm_key);

// 设置密钥权限
// 权限格式: possessor|user|group|other
// 每个字段: view|read|write|search|link|setattr|all
key_perm_t permissions = KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ;

if (keyctl(KEYCTL_SETPERM, perm_key, permissions, 0, 0) == 0) {
printf("✓ 设置密钥权限成功\n");

// 描述密钥查看权限
char desc&#91;256];
long desc_len = keyctl(KEYCTL_DESCRIBE, perm_key,
(long)desc, sizeof(desc), 0);
if (desc_len != -1) {
desc&#91;desc_len] = '\0';
printf("更新后的密钥描述: %s", desc);
}
} else {
printf("设置密钥权限失败: %s\n", strerror(errno));
}

// 更改密钥所有者(需要特权)
if (keyctl(KEYCTL_CHOWN, perm_key, getuid(), 0, 0) == 0) {
printf("✓ 更改密钥所有者成功\n");
} else {
if (errno == EPERM) {
printf("ℹ 更改所有者需要特权权限\n");
} else {
printf("更改所有者失败: %s\n", strerror(errno));
}
}

// 撤销密钥
keyctl(KEYCTL_REVOKE, perm_key, 0, 0, 0);
}

int main() {
printf("=== keyctl 密钥环操作演示 ===\n");

// 检查密钥支持
if (keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0) == -1) {
printf("错误: 系统不支持密钥保留服务\n");
return 1;
}

demonstrate_keyring_operations();
demonstrate_key_search();
demonstrate_key_permissions();

return 0;
}

示例3:密钥安全和加密操作

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
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <keyutils.h>
#include <errno.h>
#include <string.h>
#include <time.h>

void demonstrate_encrypted_keys() {
printf("=== 加密密钥演示 ===\n");

// 检查是否支持加密密钥
printf("系统支持的密钥类型:\n");
system("cat /proc/key-types 2>/dev/null | grep -E 'user|encrypted|trusted' || "
"echo '无法读取密钥类型信息'");

// 创建用户密钥(基础加密)
const char *encrypted_data = "sensitive_encrypted_data";
key_serial_t enc_key = add_key("user", "encrypted_secret",
encrypted_data, strlen(encrypted_data),
KEY_SPEC_SESSION_KEYRING);

if (enc_key != -1) {
printf("✓ 创建加密数据密钥: %d\n", enc_key);

// 设置超时以增强安全性
if (keyctl(KEYCTL_SET_TIMEOUT, enc_key, 300, 0, 0) == 0) { // 5分钟
printf("✓ 设置密钥超时为 5 分钟\n");
}

// 读取密钥数据
char buffer&#91;256];
long read_len = keyctl(KEYCTL_READ, enc_key, (long)buffer,
sizeof(buffer), 0);
if (read_len != -1) {
buffer&#91;read_len] = '\0';
printf("读取加密数据长度: %ld 字节\n", read_len);
}
} else {
printf("创建加密密钥失败: %s\n", strerror(errno));
}
}

void demonstrate_key_lifecycle() {
printf("\n=== 密钥生命周期管理 ===\n");

// 创建密钥
const char *key_data = "lifecycle_test_data";
key_serial_t key = add_key("user", "lifecycle_test",
key_data, strlen(key_data),
KEY_SPEC_SESSION_KEYRING);

if (key == -1) {
printf("创建密钥失败: %s\n", strerror(errno));
return;
}

printf("1. 创建密钥: %d\n", key);

// 描述密钥状态
char desc&#91;256];
long desc_len = keyctl(KEYCTL_DESCRIBE, key, (long)desc, sizeof(desc), 0);
if (desc_len != -1) {
desc&#91;desc_len] = '\0';
printf("2. 密钥状态: %s", desc);
}

// 更新密钥数据
const char *new_data = "updated_lifecycle_data";
if (keyctl(KEYCTL_UPDATE, key, (long)new_data, strlen(new_data), 0) == 0) {
printf("3. ✓ 更新密钥数据成功\n");
}

// 设置短期超时
if (keyctl(KEYCTL_SET_TIMEOUT, key, 10, 0, 0) == 0) { // 10秒
printf("4. ✓ 设置 10 秒超时\n");
}

// 等待几秒观察超时效果
printf("5. 等待 12 秒观察超时效果...\n");
sleep(12);

// 尝试访问已过期的密钥
char buffer&#91;256];
long read_len = keyctl(KEYCTL_READ, key, (long)buffer, sizeof(buffer), 0);
if (read_len == -1) {
if (errno == EKEYEXPIRED) {
printf("6. ✓ 密钥已正确过期\n");
} else {
printf("6. 访问密钥失败: %s\n", strerror(errno));
}
}

// 撤销密钥(即使已过期)
if (keyctl(KEYCTL_REVOKE, key, 0, 0, 0) == 0) {
printf("7. ✓ 撤销密钥成功\n");
}
}

void demonstrate_key_security_analysis() {
printf("\n=== 密钥安全分析 ===\n");

// 显示当前用户的密钥使用情况
printf("当前密钥使用情况:\n");
system("cat /proc/key-users 2>/dev/null | head -10 || echo '无法读取密钥用户信息'");

// 显示系统密钥信息
printf("\n系统密钥信息:\n");
system("cat /proc/keys 2>/dev/null | head -10 || echo '无法读取密钥信息'");

// 显示密钥配额信息
printf("\n密钥配额信息:\n");
system("cat /proc/sys/kernel/keys/* 2>/dev/null || echo '无法读取密钥配额'");

// 安全建议
printf("\n密钥安全最佳实践:\n");
printf(" • 使用适当的超时设置\n");
printf(" • 设置最小必要权限\n");
printf(" • 定期清理过期密钥\n");
printf(" • 避免在日志中记录密钥数据\n");
printf(" • 使用加密存储敏感数据\n");
printf(" • 监控密钥使用情况\n");
}

int main() {
printf("=== keyctl 安全和加密操作演示 ===\n");

// 检查密钥支持
if (keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0) == -1) {
printf("错误: 系统不支持密钥保留服务\n");
return 1;
}

printf("✓ 密钥保留服务可用\n");

demonstrate_encrypted_keys();
demonstrate_key_lifecycle();
demonstrate_key_security_analysis();

return 0;
}

示例4:密钥管理工具和监控

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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <keyutils.h>
#include <errno.h>
#include <string.h>
#include <time.h>

void show_key_statistics() {
printf("=== 密钥统计信息 ===\n");

// 显示密钥数量
printf("系统密钥统计:\n");
system("wc -l /proc/keys 2>/dev/null | awk '{print \"总密钥数: \" $1-1}' || "
"echo '无法统计密钥数量'");

// 显示密钥用户信息
printf("\n密钥用户统计:\n");
system("cat /proc/key-users 2>/dev/null | head -5 || echo '无法读取用户统计'");

// 显示密钥类型分布
printf("\n密钥类型分布:\n");
system("awk '{print $4}' /proc/keys 2>/dev/null | sort | uniq -c | head -10 || "
"echo '无法分析密钥类型'");
}

void interactive_key_manager() {
int choice;
char input&#91;256];

while (1) {
printf("\n=== 密钥管理菜单 ===\n");
printf("1. 列出当前密钥\n");
printf("2. 创建新密钥\n");
printf("3. 查找密钥\n");
printf("4. 删除密钥\n");
printf("5. 显示密钥统计\n");
printf("6. 清空会话密钥环\n");
printf("0. 退出\n");
printf("请选择操作: ");

if (scanf("%d", &choice) != 1) {
printf("输入无效,请重新选择\n");
while (getchar() != '\n'); // 清空输入缓冲区
continue;
}

switch (choice) {
case 1:
printf("当前会话密钥:\n");
system("keyctl list @s 2>/dev/null || echo '无法列出密钥'");
break;

case 2: {
printf("输入密钥描述: ");
scanf("%255s", input);

printf("输入密钥数据: ");
scanf("%255s", input + 128); // 简化处理

key_serial_t new_key = add_key("user", input,
input + 128,
strlen(input + 128),
KEY_SPEC_SESSION_KEYRING);
if (new_key != -1) {
printf("✓ 成功创建密钥: %d\n", new_key);
} else {
printf("❌ 创建密钥失败: %s\n", strerror(errno));
}
break;
}

case 3: {
printf("输入要查找的密钥描述: ");
scanf("%255s", input);

key_serial_t found_key = keyctl(KEYCTL_SEARCH,
KEY_SPEC_SESSION_KEYRING,
(long)"user", (long)input, 0);
if (found_key != -1) {
printf("✓ 找到密钥: %d\n", found_key);
} else {
printf("❌ 未找到密钥: %s\n", strerror(errno));
}
break;
}

case 4: {
printf("输入要删除的密钥 ID: ");
int key_id;
if (scanf("%d", &key_id) == 1) {
if (keyctl(KEYCTL_REVOKE, key_id, 0, 0, 0) == 0) {
printf("✓ 成功撤销密钥: %d\n", key_id);
} else {
printf("❌ 撤销密钥失败: %s\n", strerror(errno));
}
} else {
printf("输入无效\n");
}
break;
}

case 5:
show_key_statistics();
break;

case 6:
if (keyctl(KEYCTL_CLEAR, KEY_SPEC_SESSION_KEYRING, 0, 0, 0) == 0) {
printf("✓ 成功清空会话密钥环\n");
} else {
printf("❌ 清空密钥环失败: %s\n", strerror(errno));
}
break;

case 0:
printf("退出密钥管理工具\n");
return;

default:
printf("无效选择,请重新输入\n");
break;
}
}
}

void demonstrate_advanced_key_operations() {
printf("\n=== 高级密钥操作 ===\n");

// 创建密钥环
key_serial_t keyring = add_key("keyring", "advanced_test_ring",
NULL, 0, KEY_SPEC_SESSION_KEYRING);
if (keyring != -1) {
printf("✓ 创建测试密钥环: %d\n", keyring);

// 在密钥环中创建多个密钥
for (int i = 1; i <= 3; i++) {
char desc&#91;32], data&#91;32];
snprintf(desc, sizeof(desc), "key_%d", i);
snprintf(data, sizeof(data), "data_%d", i);

key_serial_t key = add_key("user", desc, data, strlen(data), keyring);
if (key != -1) {
printf(" ✓ 创建密钥 %s: %d\n", desc, key);
}
}

// 列出密钥环内容
printf("密钥环内容:\n");
char buffer&#91;1024];
long len = keyctl(KEYCTL_READ, keyring, (long)buffer, sizeof(buffer), 0);
if (len != -1) {
// 简化显示
printf(" 密钥环包含 %ld 字节数据\n", len);
}

// 清空密钥环
if (keyctl(KEYCTL_CLEAR, keyring, 0, 0, 0) == 0) {
printf("✓ 清空密钥环成功\n");
}

// 撤销密钥环
keyctl(KEYCTL_REVOKE, keyring, 0, 0, 0);
}
}

void key_monitoring_demo() {
printf("\n=== 密钥监控演示 ===\n");

printf("实时密钥监控 (按 Ctrl+C 停止):\n");

// 显示初始状态
printf("初始密钥数量: ");
system("wc -l /proc/keys 2>/dev/null | awk '{print $1-1}' || echo 'unknown'");

// 创建测试密钥并监控变化
key_serial_t test_key = add_key("user", "monitor_test",
"monitor data", 12,
KEY_SPEC_SESSION_KEYRING);
if (test_key != -1) {
printf("创建测试密钥后数量: ");
system("wc -l /proc/keys 2>/dev/null | awk '{print $1-1}' || echo 'unknown'");

// 撤销密钥
keyctl(KEYCTL_REVOKE, test_key, 0, 0, 0);
printf("撤销测试密钥后数量: ");
system("wc -l /proc/keys 2>/dev/null | awk '{print $1-1}' || echo 'unknown'");
}
}

int main() {
printf("=== keyctl 高级管理和监控工具 ===\n");

// 检查密钥支持
if (keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0) == -1) {
printf("错误: 系统不支持密钥保留服务\n");
return 1;
}

printf("✓ 密钥保留服务可用\n");

// 显示系统信息
printf("\n系统密钥信息:\n");
system("uname -a");

// 执行高级操作演示
demonstrate_advanced_key_operations();

// 显示统计信息
show_key_statistics();

// 监控演示
key_monitoring_demo();

// 启动交互式管理器(如果需要)
char choice;
printf("\n是否启动交互式密钥管理器? (y/N): ");
if (scanf(" %c", &choice) == 1 && (choice == 'y' || choice == 'Y')) {
interactive_key_manager();
}

return 0;
}

10. 密钥权限说明

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
// 密钥权限位定义
#define KEY_POS_VIEW 0x01000000 /* 持有者可查看 */
#define KEY_POS_READ 0x02000000 /* 持有者可读取 */
#define KEY_POS_WRITE 0x04000000 /* 持有者可写入 */
#define KEY_POS_SEARCH 0x08000000 /* 持有者可搜索 */
#define KEY_POS_LINK 0x10000000 /* 持有者可链接 */
#define KEY_POS_SETATTR 0x20000000 /* 持有者可设置属性 */
#define KEY_POS_ALL 0x3f000000 /* 持有者所有权限 */

#define KEY_USR_VIEW 0x00010000 /* 用户可查看 */
#define KEY_USR_READ 0x00020000 /* 用户可读取 */
#define KEY_USR_WRITE 0x00040000 /* 用户可写入 */
#define KEY_USR_SEARCH 0x00080000 /* 用户可搜索 */
#define KEY_USR_LINK 0x00100000 /* 用户可链接 */
#define KEY_USR_SETATTR 0x00200000 /* 用户可设置属性 */
#define KEY_USR_ALL 0x003f0000 /* 用户所有权限 */

#define KEY_GRP_VIEW 0x00000100 /* 组可查看 */
#define KEY_GRP_READ 0x00000200 /* 组可读取 */
#define KEY_GRP_WRITE 0x00000400 /* 组可写入 */
#define KEY_GRP_SEARCH 0x00000800 /* 组可搜索 */
#define KEY_GRP_LINK 0x00001000 /* 组可链接 */
#define KEY_GRP_SETATTR 0x00002000 /* 组可设置属性 */
#define KEY_GRP_ALL 0x00003f00 /* 组所有权限 */

#define KEY_OTH_VIEW 0x00000001 /* 其他可查看 */
#define KEY_OTH_READ 0x00000002 /* 其他可读取 */
#define KEY_OTH_WRITE 0x00000004 /* 其他可写入 */
#define KEY_OTH_SEARCH 0x00000008 /* 其他可搜索 */
#define KEY_OTH_LINK 0x00000010 /* 其他可链接 */
#define KEY_OTH_SETATTR 0x00000020 /* 其他可设置属性 */
#define KEY_OTH_ALL 0x0000003f /* 其他所有权限 */

11. 实际应用场景

场景1:网络认证

1
2
3
4
5
6
void network_authentication_keys() {
// 存储网络认证凭证
add_key("user", "wifi_password", "secret123", 9,
KEY_SPEC_SESSION_KEYRING);
}

场景2:文件系统加密

1
2
3
4
5
6
void filesystem_encryption_keys() {
// 存储加密文件系统密钥
add_key("encrypted", "fs_encryption_key", key_data, key_len,
KEY_SPEC_SESSION_KEYRING);
}

场景3:安全通信

1
2
3
4
5
6
void secure_communication_keys() {
// 存储 TLS/SSL 会话密钥
add_key("user", "tls_session_key", session_key, key_len,
KEY_SPEC_PROCESS_KEYRING);
}

12. 注意事项

使用 keyctl 时需要注意:

权限要求: 某些操作需要特殊权限

内存安全: 密钥数据在内存中的安全处理

生命周期: 正确管理密钥的创建、使用和销毁

超时设置: 合理设置密钥超时以增强安全性

权限控制: 设置最小必要权限

系统资源: 监控密钥使用对系统资源的影响

13. 系统配置检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 检查密钥支持
grep CONFIG_KEYS /boot/config-$(uname -r)

# 查看密钥信息
cat /proc/keys
cat /proc/key-users

# 检查密钥配额
cat /proc/sys/kernel/keys/maxkeys
cat /proc/sys/kernel/keys/maxbytes

# 使用 keyctl 工具
keyctl list @s
keyctl show

总结

keyctl 是 Linux 系统中强大的密钥管理接口:

关键特性:1. 安全存储: 内核级密钥安全存储2. 权限控制: 细粒度的访问控制3. 生命周期管理: 完整的密钥生命周期控制4. 多种密钥类型: 支持各种应用场景5. 系统集成: 与 Linux 安全子系统深度集成

主要应用:1. 网络认证和安全通信2. 文件系统加密3. 应用程序密钥管理4. 系统安全服务5. 容器和虚拟化安全

使用要点:1. 需要理解密钥权限模型2. 注意密钥生命周期管理3. 合理设置超时和权限4. 监控密钥使用情况5. 配合用户态工具使用效果更佳

正确使用 keyctl 可以显著提高应用程序的安全性,是现代 Linux 系统安全架构的重要组成部分。

data-ad-format="auto" data-full-width-responsive="true">