요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
Developing Cipher Algorithms
============================
Registering And Unregistering Transformation
--------------------------------------------
There are three distinct types of registration functions in the Crypto
API. One is used to register a generic cryptographic transformation,
while the other two are specific to HASH transformations and
COMPRESSion. We will discuss the latter two in a separate chapter, here
we will only look at the generic ones.
Before discussing the register functions, the data structure to be
filled with each, struct crypto_alg, must be considered -- see below
for a description of this data structure.
The generic registration functions can be found in
include/linux/crypto.h and their definition can be seen below. The
former function registers a single transformation, while the latter
works on an array of transformation descriptions. The latter is useful
when registering transformations in bulk, for example when a driver
implements multiple transformations.
::
int crypto_register_alg(struct crypto_alg *alg);
int crypto_register_algs(struct crypto_alg *algs, int count);
The counterparts to those functions are listed below.
::
void crypto_unregister_alg(struct crypto_alg *alg);
void crypto_unregister_algs(struct crypto_alg *algs, int count);
The registration functions return 0 on success, or a negative errno
value on failure. crypto_register_algs() succeeds only if it
successfully registered all the given algorithms; if it fails partway
through, then any changes are rolled back.
The unregistration functions always succeed, so they don't have a
return value. Don't try to unregister algorithms that aren't
currently registered.
Single-Block Symmetric Ciphers [CIPHER]
---------------------------------------
Example of transformations: aes, serpent, ...
This section describes the simplest of all transformation
implementations, that being the CIPHER type used for symmetric ciphers.
The CIPHER type is used for transformations which operate on exactly one
block at a time and there are no dependencies between blocks at all.
Registration specifics
~~~~~~~~~~~~~~~~~~~~~~
The registration of [CIPHER] algorithm is specific in that struct
crypto_alg field .cra_type is empty. The .cra_u.cipher has to be
filled in with proper callbacks to implement this transformation.
See struct cipher_alg below.
Cipher Definition With struct cipher_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Struct cipher_alg defines a single block cipher.
Here are schematics of how these functions are called when operated from
other part of the kernel. Note that the .cia_setkey() call might happen
before or after any of these schematics happen, but must not happen
during any of these are in-flight.
::
KEY ---. PLAINTEXT ---.
v v
.cia_setkey() -> .cia_encrypt()
|
'-----> CIPHERTEXT
Please note that a pattern where .cia_setkey() is called multiple times
is also valid:
::
KEY1 --. PLAINTEXT1 --. KEY2 --. PLAINTEXT2 --.
v v v v
.cia_setkey() -> .cia_encrypt() -> .cia_setkey() -> .cia_encrypt()
| |
'---> CIPHERTEXT1 '---> CIPHERTEXT2
Multi-Block Ciphers
-------------------
Example of transformations: cbc(aes), chacha20, ...
This section describes the multi-block cipher transformation
implementations. The multi-block ciphers are used for transformations
which operate on scatterlists of data supplied to the transformation
functions. They output the result into a scatterlist of data as well.
Registration Specifics
~~~~~~~~~~~~~~~~~~~~~~
The registration of multi-block cipher algorithms is one of the most
standard procedures throughout the crypto API.
Note, if a cipher implementation requires a proper alignment of data,
the caller should use the functions of crypto_skcipher_alignmask() to
identify a memory alignment mask. The kernel crypto API is able to
process requests that are unaligned. This implies, however, additional
overhead as the kernel crypto API needs to perform the realignment of
the data which may imply moving of data.
Cipher Definition With struct skcipher_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Struct skcipher_alg defines a multi-block cipher, or more generally, a
length-preserving symmetric cipher algorithm.
Scatterlist handling
~~~~~~~~~~~~~~~~~~~~
Some drivers will want to use the Generic ScatterWalk in case the
hardware needs to be fed separate chunks of the scatterlist which
contains the plaintext and will contain the ciphertext. Please refer
to the ScatterWalk interface offered by the Linux kernel scatter /
gather list implementation.
Hashing [HASH]
--------------
Example of transformations: crc32, md5, sha1, sha256,...
Registering And Unregistering The Transformation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are multiple ways to register a HASH transformation, depending on
whether the transformation is synchronous [SHASH] or asynchronous
[AHASH] and the amount of HASH transformations we are registering. You
can find the prototypes defined in include/crypto/internal/hash.h:
::
int crypto_register_ahash(struct ahash_alg *alg);
int crypto_register_shash(struct shash_alg *alg);
int crypto_register_shashes(struct shash_alg *algs, int count);
The respective counterparts for unregistering the HASH transformation
are as follows:
::
void crypto_unregister_ahash(struct ahash_alg *alg);
void crypto_unregister_shash(struct shash_alg *alg);
void crypto_unregister_shashes(struct shash_alg *algs, int count);
Cipher Definition With struct shash_alg and ahash_alg
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here are schematics of how these functions are called when operated from
other part of the kernel. Note that the .setkey() call might happen
before or after any of these schematics happen, but must not happen
during any of these are in-flight. Please note that calling .init()
followed immediately by .final() is also a perfectly valid
transformation.
::
I) DATA -----------.
v
.init() -> .update() -> .final() ! .update() might not be called
^ | | at all in this scenario.
'----' '---> HASH
II) DATA -----------.-----------.
v v
.init() -> .update() -> .finup() ! .update() may not be called
^ | | at all in this scenario.
'----' '---> HASH
III) DATA -----------.
v
.digest() ! The entire process is handled
| by the .digest() call.
'---------------> HASH
Here is a schematic of how the .export()/.import() functions are called
when used from another part of the kernel.
::
KEY--. DATA--.
v v ! .update() may not be called
.setkey() -> .init() -> .update() -> .export() at all in this scenario.
^ | |
'-----' '--> PARTIAL_HASH
----------- other transformations happen here -----------
PARTIAL_HASH--. DATA1--.
v v
.import -> .update() -> .final() ! .update() may not be called
^ | | at all in this scenario.
'----' '--> HASH1
PARTIAL_HASH--. DATA2-.
v v
.import -> .finup()
|
'---------------> HASH2
Note that it is perfectly legal to "abandon" a request object:
- call .init() and then (as many times) .update()
- _not_ call any of .final(), .finup() or .export() at any point in future
In other words implementations should mind the resource allocation and clean-up.
No resources related to request objects should remain allocated after a call
to .init() or .update(), since there might be no chance to free them.
Specifics Of Asynchronous HASH Transformation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some of the drivers will want to use the Generic ScatterWalk in case the
implementation needs to be fed separate chunks of the scatterlist which
contains the input data.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
암호 알고리즘 개발
1-3암호 알고리즘 개발
Transform 등록과 등록 해제
4-46Transform 등록과 등록 해제
Crypto API에는 서로 다른 세 종류의 등록 함수가 있습니다. 하나는 일반 암호 transform을 등록하고 나머지 두 종류는 HASH transform과 COMPRESSion 전용입니다. 뒤의 두 종류는 별도 장에서 다루며 여기서는 일반 등록 함수만 설명합니다.
등록 함수를 논의하기 전에 각 함수에 채워 전달할 `struct crypto_alg` data 구조를 고려해야 합니다. 이 구조는 아래에서 설명합니다.
일반 등록 함수는 `include/linux/crypto.h`에 있습니다. 첫 함수는 transform 하나를 등록하고 둘째 함수는 transform description 배열을 처리합니다. Driver가 여러 transform을 구현하여 한꺼번에 등록할 때 둘째 함수가 유용합니다.
::
int crypto_register_alg(struct crypto_alg *alg);
int crypto_register_algs(struct crypto_alg *algs, int count);
대응하는 등록 해제 함수는 다음과 같습니다.
::
void crypto_unregister_alg(struct crypto_alg *alg);
void crypto_unregister_algs(struct crypto_alg *algs, int count);
등록 함수는 성공하면 0, 실패하면 음수 errno를 반환합니다. `crypto_register_algs()`는 주어진 모든 알고리즘을 등록해야 성공하며, 중간에 실패하면 이미 적용한 변경도 rollback합니다.
등록 해제 함수는 항상 성공하므로 반환값이 없습니다. 현재 등록되지 않은 알고리즘의 등록을 해제하려고 해서는 안 됩니다.
단일 블록 대칭 암호와 등록
47-65단일 블록 대칭 암호 [CIPHER]
Transform 예: `aes`, `serpent` 등
이 절은 가장 단순한 transform 구현인 대칭 암호용 CIPHER type을 설명합니다. CIPHER type은 정확히 한 블록씩 처리하고 블록 사이 dependency가 전혀 없는 transform에 사용합니다.
등록 세부 사항
[CIPHER] 알고리즘을 등록할 때는 `struct crypto_alg`의 `.cra_type` field를 비워 둡니다. 이 transform을 구현하는 적절한 callback으로 `.cra_u.cipher`를 채워야 합니다.
아래의 `struct cipher_alg` 설명을 참조하십시오.
struct cipher_alg 정의와 호출 흐름
66-97`struct cipher_alg`을 사용하는 cipher 정의
`struct cipher_alg`은 단일 블록 암호를 정의합니다.
다음 구조도는 커널의 다른 부분에서 이 함수들이 호출되는 방식을 보여 줍니다. `.cia_setkey()`는 구조도 흐름 전이나 후에 호출할 수 있지만, 어떤 연산이 진행 중일 때 호출해서는 안 됩니다.
Key 설정 후 plaintext 한 블록을 암호화하여 ciphertext를 만듭니다.
`.cia_setkey()`를 여러 번 호출하는 pattern도 유효합니다.
각 key 설정은 대응하는 암호화가 끝난 뒤 다음 key로 교체됩니다.
다중 블록 암호
98-135다중 블록 암호
Transform 예: `cbc(aes)`, `chacha20` 등
다중 블록 암호 transform은 함수에 제공된 data scatterlist에서 연산하고 결과도 data scatterlist에 출력합니다.
등록 세부 사항
다중 블록 암호 알고리즘 등록은 Crypto API 전반에서 사용하는 가장 표준적인 절차 중 하나입니다.
암호 구현에 특정 data alignment가 필요하면 호출자는 `crypto_skcipher_alignmask()` 계열 함수로 memory alignment mask를 확인해야 합니다. 커널 Crypto API는 정렬되지 않은 request도 처리할 수 있지만 data를 옮길 수 있는 realignment 작업이 필요하므로 추가 overhead가 생깁니다.
`struct skcipher_alg`을 사용하는 cipher 정의
`struct skcipher_alg`은 다중 블록 암호, 더 일반적으로는 길이를 보존하는 대칭 암호 알고리즘을 정의합니다.
Scatterlist 처리
Hardware에 plaintext가 들어 있고 ciphertext가 들어갈 scatterlist를 분리된 chunk로 공급해야 하는 driver는 Generic ScatterWalk를 사용할 수 있습니다. Linux kernel scatter/gather list 구현이 제공하는 ScatterWalk interface를 참조하십시오.
HASH 등록과 등록 해제
136-167Hashing [HASH]
Transform 예: `crc32`, `md5`, `sha1`, `sha256` 등
Transform 등록과 등록 해제
HASH transform을 등록하는 방법은 동기 [SHASH]인지 비동기 [AHASH]인지와 등록할 HASH transform 수에 따라 여러 가지입니다. Prototype은 `include/crypto/internal/hash.h`에 정의되어 있습니다.
::
int crypto_register_ahash(struct ahash_alg *alg);
int crypto_register_shash(struct shash_alg *alg);
int crypto_register_shashes(struct shash_alg *algs, int count);
대응하는 HASH transform 등록 해제 함수는 다음과 같습니다.
::
void crypto_unregister_ahash(struct ahash_alg *alg);
void crypto_unregister_shash(struct shash_alg *alg);
void crypto_unregister_shashes(struct shash_alg *algs, int count);
struct shash_alg·ahash_alg 정의와 호출 흐름
168-232`struct shash_alg`과 `ahash_alg`을 사용하는 cipher 정의
다음 구조도는 커널의 다른 부분에서 함수가 호출되는 방식을 보여 줍니다. `.setkey()`는 이러한 흐름 전이나 후에 호출할 수 있지만 진행 중에는 호출할 수 없습니다. `.init()` 직후 `.final()`을 호출하는 것도 완전히 유효한 transform입니다.
Update는 0회 이상 호출할 수 있으며 digest는 전체 과정을 한 번에 수행합니다.
다음 구조도는 커널의 다른 부분에서 `.export()`와 `.import()`를 사용하는 방식을 보여 줍니다.
부분 상태를 export한 뒤 여러 후속 transform에서 import하여 서로 다른 hash를 완성할 수 있습니다.
Request 객체를 포기하는 것도 완전히 허용됩니다.
- `.init()`을 호출한 뒤 `.update()`를 원하는 횟수만큼 호출합니다.
- 이후 어느 시점에도 `.final()`, `.finup()`, `.export()`를 호출하지 않을 수 있습니다.
따라서 구현은 resource 할당과 정리를 주의해야 합니다. 해제할 기회가 없을 수 있으므로 `.init()` 또는 `.update()` 반환 후 request 객체 관련 resource가 할당된 채 남아서는 안 됩니다.
비동기 HASH transform 세부 사항
233-238비동기 HASH transform 세부 사항
구현에 input data scatterlist를 분리된 chunk로 공급해야 하는 driver는 Generic ScatterWalk를 사용할 수 있습니다.
요약과 해설
devel-algos.rst:1-238알고리즘 개발자는 일반 transform, CIPHER, SKCIPHER, SHASH, AHASH 각각의 등록 함수와 `struct crypto_alg`, `cipher_alg`, `skcipher_alg`, `shash_alg`, `ahash_alg` callback 계약을 맞춰야 합니다.
이 문서에서 중요한 안전 규칙은 진행 중인 연산 사이에 key를 바꾸지 않는 것, unaligned request의 realignment 비용을 고려하는 것, HASH request가 final 없이 포기될 수 있으므로 init·update 뒤에 정리되지 않은 resource를 남기지 않는 것입니다. 원문의 네 ASCII 호출 흐름은 구조화 도식으로 다시 구성했습니다.