← Documents Documentation/crypto/userspace-if.rst GitHub 원문 ↗

Linux 6.18.37 · Crypto

User Space Crypto API Interface

AF_ALG socket을 통한 message digest, skcipher, AEAD, RNG 사용법과 zero-copy 및 setsockopt 제어를 설명합니다.

Source pathDocumentation/crypto/userspace-if.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

userspace-if.rst:1-410

user space는 커널 Crypto API의 provider가 아니라 consumer로만 동작하며, `AF_ALG` socket을 생성하고 `bind`, `accept`를 거쳐 얻은 descriptor로 데이터를 송수신합니다. 요청은 user space 관점에서 synchronous입니다.

API별 `sockaddr_alg` 설정 뒤 `sendmsg`의 control message로 연산 mode, IV, AAD 길이를 전달하고 `setsockopt`로 key, AEAD tag 크기, RNG entropy를 설정합니다. in-place 처리와 page-aligned zero-copy도 지원하지만 buffer 크기, `/proc/crypto` 제약, 16-page 제한을 지켜야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 User Space Interface
2 ====================
3
4 Introduction
5 ------------
6
7 The concepts of the kernel crypto API visible to kernel space is fully
8 applicable to the user space interface as well. Therefore, the kernel
9 crypto API high level discussion for the in-kernel use cases applies
10 here as well.
11
12 The major difference, however, is that user space can only act as a
13 consumer and never as a provider of a transformation or cipher
14 algorithm.
15
16 The following covers the user space interface exported by the kernel
17 crypto API. A working example of this description is libkcapi that can
18 be obtained from [1]. That library can be used by user space
19 applications that require cryptographic services from the kernel.
20
21 Some details of the in-kernel kernel crypto API aspects do not apply to
22 user space, however. This includes the difference between synchronous
23 and asynchronous invocations. The user space API call is fully
24 synchronous.
25
26 [1] https://www.chronox.de/libkcapi.html
27
28 User Space API General Remarks
29 ------------------------------
30
31 The kernel crypto API is accessible from user space. Currently, the
32 following ciphers are accessible:
33
34 - Message digest including keyed message digest (HMAC, CMAC)
35
36 - Symmetric ciphers
37
38 - AEAD ciphers
39
40 - Random Number Generators
41
42 The interface is provided via socket type using the type AF_ALG. In
43 addition, the setsockopt option type is SOL_ALG. In case the user space
44 header files do not export these flags yet, use the following macros:
45
46 ::
47
48 #ifndef AF_ALG
49 #define AF_ALG 38
50 #endif
51 #ifndef SOL_ALG
52 #define SOL_ALG 279
53 #endif
54
55
56 A cipher is accessed with the same name as done for the in-kernel API
57 calls. This includes the generic vs. unique naming schema for ciphers as
58 well as the enforcement of priorities for generic names.
59
60 To interact with the kernel crypto API, a socket must be created by the
61 user space application. User space invokes the cipher operation with the
62 send()/write() system call family. The result of the cipher operation is
63 obtained with the read()/recv() system call family.
64
65 The following API calls assume that the socket descriptor is already
66 opened by the user space application and discusses only the kernel
67 crypto API specific invocations.
68
69 To initialize the socket interface, the following sequence has to be
70 performed by the consumer:
71
72 1. Create a socket of type AF_ALG with the struct sockaddr_alg
73 parameter specified below for the different cipher types.
74
75 2. Invoke bind with the socket descriptor
76
77 3. Invoke accept with the socket descriptor. The accept system call
78 returns a new file descriptor that is to be used to interact with the
79 particular cipher instance. When invoking send/write or recv/read
80 system calls to send data to the kernel or obtain data from the
81 kernel, the file descriptor returned by accept must be used.
82
83 In-place Cipher operation
84 -------------------------
85
86 Just like the in-kernel operation of the kernel crypto API, the user
87 space interface allows the cipher operation in-place. That means that
88 the input buffer used for the send/write system call and the output
89 buffer used by the read/recv system call may be one and the same. This
90 is of particular interest for symmetric cipher operations where a
91 copying of the output data to its final destination can be avoided.
92
93 If a consumer on the other hand wants to maintain the plaintext and the
94 ciphertext in different memory locations, all a consumer needs to do is
95 to provide different memory pointers for the encryption and decryption
96 operation.
97
98 Message Digest API
99 ------------------
100
101 The message digest type to be used for the cipher operation is selected
102 when invoking the bind syscall. bind requires the caller to provide a
103 filled struct sockaddr data structure. This data structure must be
104 filled as follows:
105
106 ::
107
108 struct sockaddr_alg sa = {
109 .salg_family = AF_ALG,
110 .salg_type = "hash", /* this selects the hash logic in the kernel */
111 .salg_name = "sha1" /* this is the cipher name */
112 };
113
114
115 The salg_type value "hash" applies to message digests and keyed message
116 digests. Though, a keyed message digest is referenced by the appropriate
117 salg_name. Please see below for the setsockopt interface that explains
118 how the key can be set for a keyed message digest.
119
120 Using the send() system call, the application provides the data that
121 should be processed with the message digest. The send system call allows
122 the following flags to be specified:
123
124 - MSG_MORE: If this flag is set, the send system call acts like a
125 message digest update function where the final hash is not yet
126 calculated. If the flag is not set, the send system call calculates
127 the final message digest immediately.
128
129 With the recv() system call, the application can read the message digest
130 from the kernel crypto API. If the buffer is too small for the message
131 digest, the flag MSG_TRUNC is set by the kernel.
132
133 In order to set a message digest key, the calling application must use
134 the setsockopt() option of ALG_SET_KEY or ALG_SET_KEY_BY_KEY_SERIAL. If the
135 key is not set the HMAC operation is performed without the initial HMAC state
136 change caused by the key.
137
138 Symmetric Cipher API
139 --------------------
140
141 The operation is very similar to the message digest discussion. During
142 initialization, the struct sockaddr data structure must be filled as
143 follows:
144
145 ::
146
147 struct sockaddr_alg sa = {
148 .salg_family = AF_ALG,
149 .salg_type = "skcipher", /* this selects the symmetric cipher */
150 .salg_name = "cbc(aes)" /* this is the cipher name */
151 };
152
153
154 Before data can be sent to the kernel using the write/send system call
155 family, the consumer must set the key. The key setting is described with
156 the setsockopt invocation below.
157
158 Using the sendmsg() system call, the application provides the data that
159 should be processed for encryption or decryption. In addition, the IV is
160 specified with the data structure provided by the sendmsg() system call.
161
162 The sendmsg system call parameter of struct msghdr is embedded into the
163 struct cmsghdr data structure. See recv(2) and cmsg(3) for more
164 information on how the cmsghdr data structure is used together with the
165 send/recv system call family. That cmsghdr data structure holds the
166 following information specified with a separate header instances:
167
168 - specification of the cipher operation type with one of these flags:
169
170 - ALG_OP_ENCRYPT - encryption of data
171
172 - ALG_OP_DECRYPT - decryption of data
173
174 - specification of the IV information marked with the flag ALG_SET_IV
175
176 The send system call family allows the following flag to be specified:
177
178 - MSG_MORE: If this flag is set, the send system call acts like a
179 cipher update function where more input data is expected with a
180 subsequent invocation of the send system call.
181
182 Note: The kernel reports -EINVAL for any unexpected data. The caller
183 must make sure that all data matches the constraints given in
184 /proc/crypto for the selected cipher.
185
186 With the recv() system call, the application can read the result of the
187 cipher operation from the kernel crypto API. The output buffer must be
188 at least as large as to hold all blocks of the encrypted or decrypted
189 data. If the output data size is smaller, only as many blocks are
190 returned that fit into that output buffer size.
191
192 AEAD Cipher API
193 ---------------
194
195 The operation is very similar to the symmetric cipher discussion. During
196 initialization, the struct sockaddr data structure must be filled as
197 follows:
198
199 ::
200
201 struct sockaddr_alg sa = {
202 .salg_family = AF_ALG,
203 .salg_type = "aead", /* this selects the symmetric cipher */
204 .salg_name = "gcm(aes)" /* this is the cipher name */
205 };
206
207
208 Before data can be sent to the kernel using the write/send system call
209 family, the consumer must set the key. The key setting is described with
210 the setsockopt invocation below.
211
212 In addition, before data can be sent to the kernel using the write/send
213 system call family, the consumer must set the authentication tag size.
214 To set the authentication tag size, the caller must use the setsockopt
215 invocation described below.
216
217 Using the sendmsg() system call, the application provides the data that
218 should be processed for encryption or decryption. In addition, the IV is
219 specified with the data structure provided by the sendmsg() system call.
220
221 The sendmsg system call parameter of struct msghdr is embedded into the
222 struct cmsghdr data structure. See recv(2) and cmsg(3) for more
223 information on how the cmsghdr data structure is used together with the
224 send/recv system call family. That cmsghdr data structure holds the
225 following information specified with a separate header instances:
226
227 - specification of the cipher operation type with one of these flags:
228
229 - ALG_OP_ENCRYPT - encryption of data
230
231 - ALG_OP_DECRYPT - decryption of data
232
233 - specification of the IV information marked with the flag ALG_SET_IV
234
235 - specification of the associated authentication data (AAD) with the
236 flag ALG_SET_AEAD_ASSOCLEN. The AAD is sent to the kernel together
237 with the plaintext / ciphertext. See below for the memory structure.
238
239 The send system call family allows the following flag to be specified:
240
241 - MSG_MORE: If this flag is set, the send system call acts like a
242 cipher update function where more input data is expected with a
243 subsequent invocation of the send system call.
244
245 Note: The kernel reports -EINVAL for any unexpected data. The caller
246 must make sure that all data matches the constraints given in
247 /proc/crypto for the selected cipher.
248
249 With the recv() system call, the application can read the result of the
250 cipher operation from the kernel crypto API. The output buffer must be
251 at least as large as defined with the memory structure below. If the
252 output data size is smaller, the cipher operation is not performed.
253
254 The authenticated decryption operation may indicate an integrity error.
255 Such breach in integrity is marked with the -EBADMSG error code.
256
257 AEAD Memory Structure
258 ~~~~~~~~~~~~~~~~~~~~~
259
260 The AEAD cipher operates with the following information that is
261 communicated between user and kernel space as one data stream:
262
263 - plaintext or ciphertext
264
265 - associated authentication data (AAD)
266
267 - authentication tag
268
269 The sizes of the AAD and the authentication tag are provided with the
270 sendmsg and setsockopt calls (see there). As the kernel knows the size
271 of the entire data stream, the kernel is now able to calculate the right
272 offsets of the data components in the data stream.
273
274 The user space caller must arrange the aforementioned information in the
275 following order:
276
277 - AEAD encryption input: AAD \|\| plaintext
278
279 - AEAD decryption input: AAD \|\| ciphertext \|\| authentication tag
280
281 The output buffer the user space caller provides must be at least as
282 large to hold the following data:
283
284 - AEAD encryption output: ciphertext \|\| authentication tag
285
286 - AEAD decryption output: plaintext
287
288 Random Number Generator API
289 ---------------------------
290
291 Again, the operation is very similar to the other APIs. During
292 initialization, the struct sockaddr data structure must be filled as
293 follows:
294
295 ::
296
297 struct sockaddr_alg sa = {
298 .salg_family = AF_ALG,
299 .salg_type = "rng", /* this selects the random number generator */
300 .salg_name = "drbg_nopr_sha256" /* this is the RNG name */
301 };
302
303
304 Depending on the RNG type, the RNG must be seeded. The seed is provided
305 using the setsockopt interface to set the key. For example, the
306 ansi_cprng requires a seed. The DRBGs do not require a seed, but may be
307 seeded. The seed is also known as a *Personalization String* in NIST SP 800-90A
308 standard.
309
310 Using the read()/recvmsg() system calls, random numbers can be obtained.
311 The kernel generates at most 128 bytes in one call. If user space
312 requires more data, multiple calls to read()/recvmsg() must be made.
313
314 WARNING: The user space caller may invoke the initially mentioned accept
315 system call multiple times. In this case, the returned file descriptors
316 have the same state.
317
318 Following CAVP testing interfaces are enabled when kernel is built with
319 CRYPTO_USER_API_RNG_CAVP option:
320
321 - the concatenation of *Entropy* and *Nonce* can be provided to the RNG via
322 ALG_SET_DRBG_ENTROPY setsockopt interface. Setting the entropy requires
323 CAP_SYS_ADMIN permission.
324
325 - *Additional Data* can be provided using the send()/sendmsg() system calls,
326 but only after the entropy has been set.
327
328 Zero-Copy Interface
329 -------------------
330
331 In addition to the send/write/read/recv system call family, the AF_ALG
332 interface can be accessed with the zero-copy interface of
333 splice/vmsplice. As the name indicates, the kernel tries to avoid a copy
334 operation into kernel space.
335
336 The zero-copy operation requires data to be aligned at the page
337 boundary. Non-aligned data can be used as well, but may require more
338 operations of the kernel which would defeat the speed gains obtained
339 from the zero-copy interface.
340
341 The system-inherent limit for the size of one zero-copy operation is 16
342 pages. If more data is to be sent to AF_ALG, user space must slice the
343 input into segments with a maximum size of 16 pages.
344
345 Zero-copy can be used with the following code example (a complete
346 working example is provided with libkcapi):
347
348 ::
349
350 int pipes[2];
351
352 pipe(pipes);
353 /* input data in iov */
354 vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
355 /* opfd is the file descriptor returned from accept() system call */
356 splice(pipes[0], NULL, opfd, NULL, ret, 0);
357 read(opfd, out, outlen);
358
359
360 Setsockopt Interface
361 --------------------
362
363 In addition to the read/recv and send/write system call handling to send
364 and retrieve data subject to the cipher operation, a consumer also needs
365 to set the additional information for the cipher operation. This
366 additional information is set using the setsockopt system call that must
367 be invoked with the file descriptor of the open cipher (i.e. the file
368 descriptor returned by the accept system call).
369
370 Each setsockopt invocation must use the level SOL_ALG.
371
372 The setsockopt interface allows setting the following data using the
373 mentioned optname:
374
375 - ALG_SET_KEY -- Setting the key. Key setting is applicable to:
376
377 - the skcipher cipher type (symmetric ciphers)
378
379 - the hash cipher type (keyed message digests)
380
381 - the AEAD cipher type
382
383 - the RNG cipher type to provide the seed
384
385 - ALG_SET_KEY_BY_KEY_SERIAL -- Setting the key via keyring key_serial_t.
386 This operation behaves the same as ALG_SET_KEY. The decrypted
387 data is copied from a keyring key, and uses that data as the
388 key for symmetric encryption.
389
390 The passed in key_serial_t must have the KEY_(POS|USR|GRP|OTH)_SEARCH
391 permission set, otherwise -EPERM is returned. Supports key types: user,
392 logon, encrypted, and trusted.
393
394 - ALG_SET_AEAD_AUTHSIZE -- Setting the authentication tag size for
395 AEAD ciphers. For a encryption operation, the authentication tag of
396 the given size will be generated. For a decryption operation, the
397 provided ciphertext is assumed to contain an authentication tag of
398 the given size (see section about AEAD memory layout below).
399
400 - ALG_SET_DRBG_ENTROPY -- Setting the entropy of the random number generator.
401 This option is applicable to RNG cipher type only.
402
403 User space API example
404 ----------------------
405
406 Please see [1] for libkcapi which provides an easy-to-use wrapper around
407 the aforementioned Netlink kernel interface. [1] also contains a test
408 application that invokes all libkcapi API calls.
409
410 [1] https://www.chronox.de/libkcapi.html
411

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

user space 인터페이스 소개

1-27

User Space 인터페이스

소개

kernel space에 공개되는 커널 Crypto API 개념은 user space 인터페이스에도 그대로 적용됩니다. 따라서 in-kernel 사용 사례에 관한 커널 Crypto API의 상위 수준 설명도 여기에 적용됩니다.

다만 가장 큰 차이는 user space가 consumer로만 동작할 수 있고 transformation 또는 cipher 알고리즘의 provider가 될 수 없다는 점입니다.

이 문서는 커널 Crypto API가 export하는 user space 인터페이스를 다룹니다. 설명대로 동작하는 예제는 [1]의 libkcapi에서 얻을 수 있으며, kernel의 암호화 서비스가 필요한 user space application에서 이 library를 사용할 수 있습니다.

in-kernel 커널 Crypto API의 일부 세부 사항은 user space에 적용되지 않습니다. synchronous 호출과 asynchronous 호출의 구분이 그 예이며, user space API 호출은 완전히 synchronous입니다.

[1] https://www.chronox.de/libkcapi.html

user space API 일반 사항

28-55

User Space API 일반 사항

커널 Crypto API는 user space에서 접근할 수 있습니다. 현재 다음 cipher를 사용할 수 있습니다.

  • keyed message digest(HMAC, CMAC)를 포함한 message digest
  • symmetric cipher
  • AEAD cipher
  • random number generator

인터페이스는 `AF_ALG` type의 socket으로 제공됩니다. `setsockopt` option type은 `SOL_ALG`입니다. user space header file이 아직 이 flag를 export하지 않는다면 다음 macro를 사용합니다.

#ifndef AF_ALG
#define AF_ALG 38
#endif
#ifndef SOL_ALG
#define SOL_ALG 279
#endif

cipher 이름과 socket 초기화

56-82

cipher는 in-kernel API 호출과 같은 이름으로 접근합니다. 여기에는 cipher의 generic 이름과 unique 이름 체계, generic 이름에 대한 priority 적용이 포함됩니다.

커널 Crypto API와 상호 작용하려면 user space application이 socket을 생성해야 합니다. user space는 `send()`/`write()` system call 계열로 cipher 연산을 요청하고 `read()`/`recv()` 계열로 연산 결과를 얻습니다.

아래 API 호출은 user space application이 socket descriptor를 이미 열었다고 가정하며, 커널 Crypto API에 특화된 호출만 설명합니다.

socket 인터페이스를 초기화하려면 consumer가 다음 순서를 수행해야 합니다.

  • 아래 cipher type별 `struct sockaddr_alg` parameter를 지정해 `AF_ALG` type socket을 생성합니다.
  • socket descriptor로 `bind`를 호출합니다.
  • socket descriptor로 `accept`를 호출합니다. `accept`가 반환한 새 file descriptor는 특정 cipher instance와 상호 작용하는 데 사용합니다. kernel에 데이터를 보내는 `send`/`write` 또는 kernel에서 데이터를 받는 `recv`/`read` 호출에는 반드시 이 descriptor를 사용해야 합니다.

in-place cipher 연산

83-97

In-place cipher 연산

in-kernel 커널 Crypto API 연산과 마찬가지로 user space 인터페이스도 in-place cipher 연산을 허용합니다. 즉, `send`/`write`에 쓰는 입력 buffer와 `read`/`recv`에 쓰는 출력 buffer가 같아도 됩니다. 출력 데이터를 최종 목적지로 복사하는 작업을 피할 수 있어 symmetric cipher 연산에서 특히 유용합니다.

반대로 consumer가 plaintext와 ciphertext를 서로 다른 memory 위치에 유지하려면 encryption과 decryption 연산에 서로 다른 memory pointer를 제공하면 됩니다.

message digest API

98-137

Message Digest API

cipher 연산에 사용할 message digest type은 `bind` syscall을 호출할 때 선택합니다. `bind`에는 채워진 `struct sockaddr` data structure를 전달해야 하며 다음과 같이 구성합니다.

struct sockaddr_alg sa = {
    .salg_family = AF_ALG,
    .salg_type = "hash", /* this selects the hash logic in the kernel */
    .salg_name = "sha1" /* this is the cipher name */
};

`salg_type` 값 "hash"는 message digest와 keyed message digest에 적용됩니다. keyed message digest는 해당 `salg_name`으로 지정합니다. key 설정 방법은 아래 `setsockopt` 인터페이스 설명을 참조하십시오.

`send()` system call로 application이 message digest 처리 대상 데이터를 제공합니다. 다음 flag를 지정할 수 있습니다.

  • `MSG_MORE`: 이 flag가 설정되면 `send`는 최종 hash를 아직 계산하지 않는 message digest update 함수처럼 동작합니다. 설정하지 않으면 `send`가 즉시 최종 message digest를 계산합니다.

`recv()` system call로 커널 Crypto API에서 message digest를 읽습니다. buffer가 message digest를 담기에 너무 작으면 kernel이 `MSG_TRUNC` flag를 설정합니다.

message digest key를 설정하려면 application이 `ALG_SET_KEY` 또는 `ALG_SET_KEY_BY_KEY_SERIAL` option으로 `setsockopt()`를 호출해야 합니다. key를 설정하지 않으면 key 때문에 발생하는 초기 HMAC state 변경 없이 HMAC 연산을 수행합니다.

symmetric cipher API

138-191

Symmetric Cipher API

연산은 message digest 방식과 매우 비슷합니다. 초기화할 때 `struct sockaddr` data structure를 다음과 같이 채웁니다.

struct sockaddr_alg sa = {
    .salg_family = AF_ALG,
    .salg_type = "skcipher", /* this selects the symmetric cipher */
    .salg_name = "cbc(aes)" /* this is the cipher name */
};

`write`/`send` system call 계열로 kernel에 데이터를 보내기 전에 consumer가 key를 설정해야 합니다. key 설정은 아래 `setsockopt` 호출에서 설명합니다.

`sendmsg()`로 encryption 또는 decryption할 데이터를 제공합니다. IV도 `sendmsg()`가 제공하는 data structure에 지정합니다.

`sendmsg` parameter인 `struct msghdr`는 `struct cmsghdr` data structure 안에 포함됩니다. `cmsghdr`를 `send`/`recv` 계열과 함께 사용하는 방법은 `recv(2)`와 `cmsg(3)`을 참조하십시오. 별도 header instance로 다음 정보를 담습니다.

  • `ALG_OP_ENCRYPT`: data encryption을 지정하는 cipher 연산 flag
  • `ALG_OP_DECRYPT`: data decryption을 지정하는 cipher 연산 flag
  • `ALG_SET_IV`: IV 정보를 지정하는 flag

`send` system call 계열에는 다음 flag를 지정할 수 있습니다.

  • `MSG_MORE`: 이 flag가 설정되면 이후 `send` 호출로 입력 데이터가 더 들어올 것을 기대하는 cipher update 함수처럼 동작합니다.

참고: 예상하지 않은 데이터가 들어오면 kernel은 `-EINVAL`을 보고합니다. caller는 모든 데이터가 선택한 cipher의 `/proc/crypto` 제약과 일치하도록 해야 합니다.

`recv()`로 커널 Crypto API에서 cipher 연산 결과를 읽습니다. 출력 buffer는 encrypt 또는 decrypt된 데이터의 모든 block을 담을 만큼 커야 합니다. 더 작으면 출력 buffer에 들어가는 block 수만큼만 반환합니다.

AEAD cipher 초기화

192-216

AEAD Cipher API

연산은 symmetric cipher 방식과 매우 비슷합니다. 초기화할 때 `struct sockaddr` data structure를 다음과 같이 채웁니다.

struct sockaddr_alg sa = {
    .salg_family = AF_ALG,
    .salg_type = "aead", /* this selects the symmetric cipher */
    .salg_name = "gcm(aes)" /* this is the cipher name */
};

`write`/`send` 계열로 kernel에 데이터를 보내기 전에 consumer가 key를 설정해야 합니다. key 설정은 아래 `setsockopt` 호출에서 설명합니다.

또한 데이터를 보내기 전에 authentication tag 크기를 설정해야 합니다. caller는 아래에서 설명하는 `setsockopt` 호출을 사용합니다.

AEAD 요청과 오류 처리

217-256

`sendmsg()`로 encryption 또는 decryption할 데이터를 제공하고, `sendmsg()`의 data structure에 IV를 지정합니다.

`sendmsg` parameter인 `struct msghdr`는 `struct cmsghdr` 안에 포함됩니다. 사용법은 `recv(2)`와 `cmsg(3)`을 참조하십시오. 별도 header instance로 다음 정보를 담습니다.

  • `ALG_OP_ENCRYPT`: data encryption을 지정하는 cipher 연산 flag
  • `ALG_OP_DECRYPT`: data decryption을 지정하는 cipher 연산 flag
  • `ALG_SET_IV`: IV 정보를 지정하는 flag
  • `ALG_SET_AEAD_ASSOCLEN`: associated authentication data(AAD)를 지정하는 flag. AAD는 plaintext 또는 ciphertext와 함께 kernel로 전송되며 memory 구조는 아래에서 설명합니다.

`send` system call 계열에는 다음 flag를 지정할 수 있습니다.

  • `MSG_MORE`: 이 flag가 설정되면 이후 `send` 호출로 입력 데이터가 더 들어올 것을 기대하는 cipher update 함수처럼 동작합니다.

참고: 예상하지 않은 데이터가 들어오면 kernel은 `-EINVAL`을 보고합니다. caller는 모든 데이터가 선택한 cipher의 `/proc/crypto` 제약과 일치하도록 해야 합니다.

`recv()`로 커널 Crypto API에서 cipher 연산 결과를 읽습니다. 출력 buffer는 아래 memory structure에서 정의한 크기 이상이어야 하며, 더 작으면 cipher 연산을 수행하지 않습니다.

authenticated decryption 연산은 integrity error를 나타낼 수 있습니다. integrity가 깨지면 `-EBADMSG` error code로 표시합니다.

AEAD memory structure

257-287

AEAD Memory Structure

AEAD cipher는 user space와 kernel space 사이에서 하나의 data stream으로 전달되는 다음 정보를 사용합니다.

  • plaintext 또는 ciphertext
  • associated authentication data(AAD)
  • authentication tag

AAD와 authentication tag의 크기는 `sendmsg` 및 `setsockopt` 호출로 제공합니다. kernel은 전체 data stream 크기를 알고 있으므로 각 구성 요소의 올바른 offset을 계산할 수 있습니다.

user space caller는 입력 정보를 다음 순서로 배치해야 합니다.

  • AEAD encryption 입력: `AAD || plaintext`
  • AEAD decryption 입력: `AAD || ciphertext || authentication tag`

caller가 제공하는 출력 buffer는 다음 데이터를 담을 만큼 커야 합니다.

  • AEAD encryption 출력: `ciphertext || authentication tag`
  • AEAD decryption 출력: `plaintext`

random number generator API

288-317

Random Number Generator API

다른 API와 마찬가지로 초기화할 때 `struct sockaddr` data structure를 다음과 같이 채웁니다.

struct sockaddr_alg sa = {
    .salg_family = AF_ALG,
    .salg_type = "rng", /* this selects the random number generator */
    .salg_name = "drbg_nopr_sha256" /* this is the RNG name */
};

RNG type에 따라 seed가 필요합니다. seed는 key를 설정하는 `setsockopt` 인터페이스로 제공합니다. 예를 들어 `ansi_cprng`에는 seed가 필요합니다. DRBG에는 seed가 필수는 아니지만 제공할 수 있습니다. NIST SP 800-90A 표준에서는 seed를 Personalization String이라고도 합니다.

`read()`/`recvmsg()`로 random number를 얻습니다. kernel은 한 번의 호출에서 최대 128 byte를 생성하므로 더 많은 데이터가 필요하면 여러 번 호출해야 합니다.

경고: user space caller는 앞서 설명한 `accept`를 여러 번 호출할 수 있습니다. 이 경우 반환된 file descriptor들은 동일한 state를 공유합니다.

RNG CAVP test 인터페이스

318-327

kernel을 `CRYPTO_USER_API_RNG_CAVP` option으로 build하면 다음 CAVP test 인터페이스가 활성화됩니다.

  • Entropy와 Nonce를 이어 붙인 값을 `ALG_SET_DRBG_ENTROPY` setsockopt 인터페이스로 RNG에 제공할 수 있습니다. entropy 설정에는 `CAP_SYS_ADMIN` 권한이 필요합니다.
  • Additional Data는 `send()`/`sendmsg()`로 제공할 수 있지만 entropy를 설정한 뒤에만 가능합니다.

zero-copy 인터페이스

328-359

Zero-Copy Interface

`send`/`write`/`read`/`recv` 계열뿐 아니라 `splice`/`vmsplice`의 zero-copy 인터페이스로도 `AF_ALG`에 접근할 수 있습니다. 이름처럼 kernel은 kernel space로의 copy 연산을 피하려고 합니다.

zero-copy 연산은 data가 page boundary에 정렬되어 있어야 합니다. 정렬되지 않은 데이터도 사용할 수 있지만 kernel 연산이 늘어나 zero-copy로 얻은 성능 이점이 사라질 수 있습니다.

한 번의 zero-copy 연산에 적용되는 system 고유 크기 제한은 16 page입니다. 더 많은 데이터를 `AF_ALG`에 보내려면 user space가 입력을 최대 16 page 크기의 segment로 나눠야 합니다.

다음은 zero-copy 사용 예제이며, 완전히 동작하는 예제는 libkcapi에서 제공합니다.

int pipes[2];

pipe(pipes);
/* input data in iov */
vmsplice(pipes[1], iov, iovlen, SPLICE_F_GIFT);
/* opfd is the file descriptor returned from accept() system call */
splice(pipes[0], NULL, opfd, NULL, ret, 0);
read(opfd, out, outlen);

setsockopt 인터페이스

360-402

Setsockopt Interface

consumer는 cipher 연산 대상 데이터를 보내고 받는 `read`/`recv` 및 `send`/`write` 처리 외에도 연산에 필요한 추가 정보를 설정해야 합니다. 이 정보는 열린 cipher의 file descriptor, 즉 `accept`가 반환한 descriptor로 `setsockopt`를 호출해 설정합니다.

모든 `setsockopt` 호출은 level로 `SOL_ALG`를 사용해야 합니다.

`setsockopt` 인터페이스는 다음 optname으로 데이터를 설정합니다.

  • `ALG_SET_KEY`: key를 설정합니다. skcipher(symmetric cipher), hash(keyed message digest), AEAD, seed를 제공하는 RNG cipher type에 적용됩니다.
  • `ALG_SET_KEY_BY_KEY_SERIAL`: keyring의 `key_serial_t`를 통해 key를 설정하며 `ALG_SET_KEY`와 동일하게 동작합니다. keyring key에서 복호화한 데이터를 복사해 symmetric encryption key로 사용합니다.
  • `ALG_SET_KEY_BY_KEY_SERIAL`에 전달한 `key_serial_t`에는 `KEY_(POS|USR|GRP|OTH)_SEARCH` 권한이 있어야 하며, 없으면 `-EPERM`을 반환합니다. user, logon, encrypted, trusted key type을 지원합니다.
  • `ALG_SET_AEAD_AUTHSIZE`: AEAD cipher의 authentication tag 크기를 설정합니다. encryption은 지정한 크기의 tag를 생성하고, decryption은 제공된 ciphertext에 그 크기의 tag가 포함되었다고 가정합니다.
  • `ALG_SET_DRBG_ENTROPY`: random number generator의 entropy를 설정하며 RNG cipher type에만 적용됩니다.

user space API 예제

403-410

User space API 예제

[1]의 libkcapi는 앞서 설명한 Netlink kernel 인터페이스를 쉽게 사용할 수 있게 감싸는 wrapper입니다. 같은 위치에 모든 libkcapi API 호출을 실행하는 test application도 있습니다.

[1] https://www.chronox.de/libkcapi.html