← Documents Documentation/crypto/api-samples.rst GitHub 원문 ↗

Linux 6.18.37 · Crypto

Code Examples

AES-256-XTS in-place symmetric encryption, SHASH descriptor state memory 할당, Hash DRBG 기반 random byte 생성의 완전한 kernel code 예제를 제공합니다.

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

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

1. 요약·해설

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

요약과 해설

api-samples.rst:1-187

세 예제는 Crypto API object 수명 관리의 공통 pattern을 보여 줍니다. Transform을 할당하고 algorithm parameter를 설정한 뒤 request 또는 descriptor를 준비해 operation을 실행하고 모든 resource를 역순으로 해제합니다.

SKCIPHER 예제는 scatterlist와 asynchronous completion wait를, SHASH 예제는 algorithm별 descriptor context size를, RNG 예제는 DRBG transform과 byte generation 반환값 처리를 집중적으로 다룹니다.

Code block은 함수명, flag, error path, 주석과 indentation을 포함하여 source 그대로 보존했습니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 Code Examples
2 =============
3
4 Code Example For Symmetric Key Cipher Operation
5 -----------------------------------------------
6
7 This code encrypts some data with AES-256-XTS. For sake of example,
8 all inputs are random bytes, the encryption is done in-place, and it's
9 assumed the code is running in a context where it can sleep.
10
11 ::
12
13 static int test_skcipher(void)
14 {
15 struct crypto_skcipher *tfm = NULL;
16 struct skcipher_request *req = NULL;
17 u8 *data = NULL;
18 const size_t datasize = 512; /* data size in bytes */
19 struct scatterlist sg;
20 DECLARE_CRYPTO_WAIT(wait);
21 u8 iv[16]; /* AES-256-XTS takes a 16-byte IV */
22 u8 key[64]; /* AES-256-XTS takes a 64-byte key */
23 int err;
24
25 /*
26 * Allocate a tfm (a transformation object) and set the key.
27 *
28 * In real-world use, a tfm and key are typically used for many
29 * encryption/decryption operations. But in this example, we'll just do a
30 * single encryption operation with it (which is not very efficient).
31 */
32
33 tfm = crypto_alloc_skcipher("xts(aes)", 0, 0);
34 if (IS_ERR(tfm)) {
35 pr_err("Error allocating xts(aes) handle: %ld\n", PTR_ERR(tfm));
36 return PTR_ERR(tfm);
37 }
38
39 get_random_bytes(key, sizeof(key));
40 err = crypto_skcipher_setkey(tfm, key, sizeof(key));
41 if (err) {
42 pr_err("Error setting key: %d\n", err);
43 goto out;
44 }
45
46 /* Allocate a request object */
47 req = skcipher_request_alloc(tfm, GFP_KERNEL);
48 if (!req) {
49 err = -ENOMEM;
50 goto out;
51 }
52
53 /* Prepare the input data */
54 data = kmalloc(datasize, GFP_KERNEL);
55 if (!data) {
56 err = -ENOMEM;
57 goto out;
58 }
59 get_random_bytes(data, datasize);
60
61 /* Initialize the IV */
62 get_random_bytes(iv, sizeof(iv));
63
64 /*
65 * Encrypt the data in-place.
66 *
67 * For simplicity, in this example we wait for the request to complete
68 * before proceeding, even if the underlying implementation is asynchronous.
69 *
70 * To decrypt instead of encrypt, just change crypto_skcipher_encrypt() to
71 * crypto_skcipher_decrypt().
72 */
73 sg_init_one(&sg, data, datasize);
74 skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
75 CRYPTO_TFM_REQ_MAY_SLEEP,
76 crypto_req_done, &wait);
77 skcipher_request_set_crypt(req, &sg, &sg, datasize, iv);
78 err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
79 if (err) {
80 pr_err("Error encrypting data: %d\n", err);
81 goto out;
82 }
83
84 pr_debug("Encryption was successful\n");
85 out:
86 crypto_free_skcipher(tfm);
87 skcipher_request_free(req);
88 kfree(data);
89 return err;
90 }
91
92
93 Code Example For Use of Operational State Memory With SHASH
94 -----------------------------------------------------------
95
96 ::
97
98
99 struct sdesc {
100 struct shash_desc shash;
101 char ctx[];
102 };
103
104 static struct sdesc *init_sdesc(struct crypto_shash *alg)
105 {
106 struct sdesc *sdesc;
107 int size;
108
109 size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
110 sdesc = kmalloc(size, GFP_KERNEL);
111 if (!sdesc)
112 return ERR_PTR(-ENOMEM);
113 sdesc->shash.tfm = alg;
114 return sdesc;
115 }
116
117 static int calc_hash(struct crypto_shash *alg,
118 const unsigned char *data, unsigned int datalen,
119 unsigned char *digest)
120 {
121 struct sdesc *sdesc;
122 int ret;
123
124 sdesc = init_sdesc(alg);
125 if (IS_ERR(sdesc)) {
126 pr_info("can't alloc sdesc\n");
127 return PTR_ERR(sdesc);
128 }
129
130 ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
131 kfree(sdesc);
132 return ret;
133 }
134
135 static int test_hash(const unsigned char *data, unsigned int datalen,
136 unsigned char *digest)
137 {
138 struct crypto_shash *alg;
139 char *hash_alg_name = "sha1-padlock-nano";
140 int ret;
141
142 alg = crypto_alloc_shash(hash_alg_name, 0, 0);
143 if (IS_ERR(alg)) {
144 pr_info("can't alloc alg %s\n", hash_alg_name);
145 return PTR_ERR(alg);
146 }
147 ret = calc_hash(alg, data, datalen, digest);
148 crypto_free_shash(alg);
149 return ret;
150 }
151
152
153 Code Example For Random Number Generator Usage
154 ----------------------------------------------
155
156 ::
157
158
159 static int get_random_numbers(u8 *buf, unsigned int len)
160 {
161 struct crypto_rng *rng = NULL;
162 char *drbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */
163 int ret;
164
165 if (!buf || !len) {
166 pr_debug("No output buffer provided\n");
167 return -EINVAL;
168 }
169
170 rng = crypto_alloc_rng(drbg, 0, 0);
171 if (IS_ERR(rng)) {
172 pr_debug("could not allocate RNG handle for %s\n", drbg);
173 return PTR_ERR(rng);
174 }
175
176 ret = crypto_rng_get_bytes(rng, buf, len);
177 if (ret < 0)
178 pr_debug("generation of random numbers failed\n");
179 else if (ret == 0)
180 pr_debug("RNG returned no data");
181 else
182 pr_debug("RNG returned %d bytes of data\n", ret);
183
184 out:
185 crypto_free_rng(rng);
186 return ret;
187 }
188

3. 한국어 전문 번역

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

Code 예제

1-3

Code 예제

Symmetric key cipher operation 예제

4-92

Symmetric key cipher operation code 예제

이 code는 AES-256-XTS로 data를 encrypt합니다. 예제를 위해 모든 input은 random byte이고 encryption은 in-place로 수행하며, code가 sleep할 수 있는 context에서 실행된다고 가정합니다.

`crypto_alloc_skcipher("xts(aes)", 0, 0)`로 transform을 할당하고 64-byte key를 설정합니다. `skcipher_request_alloc()`로 request를 만들고 512-byte data와 16-byte IV를 준비합니다.

하나의 scatterlist를 input과 output으로 함께 연결하고 `CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP` callback flag를 설정합니다. `crypto_wait_req(crypto_skcipher_encrypt(req), &wait)`로 asynchronous 구현도 완료될 때까지 기다립니다. Decrypt하려면 `crypto_skcipher_encrypt()`를 `crypto_skcipher_decrypt()`로 바꿉니다.

마지막에는 `crypto_free_skcipher()`, `skcipher_request_free()`, `kfree()`로 transform, request, data를 모두 해제합니다.

static int test_skcipher(void)
{
        struct crypto_skcipher *tfm = NULL;
        struct skcipher_request *req = NULL;
        u8 *data = NULL;
        const size_t datasize = 512; /* data size in bytes */
        struct scatterlist sg;
        DECLARE_CRYPTO_WAIT(wait);
        u8 iv[16];  /* AES-256-XTS takes a 16-byte IV */
        u8 key[64]; /* AES-256-XTS takes a 64-byte key */
        int err;

        /*
         * Allocate a tfm (a transformation object) and set the key.
         *
         * In real-world use, a tfm and key are typically used for many
         * encryption/decryption operations.  But in this example, we'll just do a
         * single encryption operation with it (which is not very efficient).
         */

        tfm = crypto_alloc_skcipher("xts(aes)", 0, 0);
        if (IS_ERR(tfm)) {
                pr_err("Error allocating xts(aes) handle: %ld\n", PTR_ERR(tfm));
                return PTR_ERR(tfm);
        }

        get_random_bytes(key, sizeof(key));
        err = crypto_skcipher_setkey(tfm, key, sizeof(key));
        if (err) {
                pr_err("Error setting key: %d\n", err);
                goto out;
        }

        /* Allocate a request object */
        req = skcipher_request_alloc(tfm, GFP_KERNEL);
        if (!req) {
                err = -ENOMEM;
                goto out;
        }

        /* Prepare the input data */
        data = kmalloc(datasize, GFP_KERNEL);
        if (!data) {
                err = -ENOMEM;
                goto out;
        }
        get_random_bytes(data, datasize);

        /* Initialize the IV */
        get_random_bytes(iv, sizeof(iv));

        /*
         * Encrypt the data in-place.
         *
         * For simplicity, in this example we wait for the request to complete
         * before proceeding, even if the underlying implementation is asynchronous.
         *
         * To decrypt instead of encrypt, just change crypto_skcipher_encrypt() to
         * crypto_skcipher_decrypt().
         */
        sg_init_one(&sg, data, datasize);
        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, &sg, datasize, iv);
        err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
        if (err) {
                pr_err("Error encrypting data: %d\n", err);
                goto out;
        }

        pr_debug("Encryption was successful\n");
out:
        crypto_free_skcipher(tfm);
        skcipher_request_free(req);
        kfree(data);
        return err;
}

SHASH operational state memory 예제

93-152

SHASH에서 operational state memory를 사용하는 code 예제

`struct sdesc`는 `struct shash_desc` 뒤에 flexible array `ctx[]`를 배치합니다. `init_sdesc()`는 `sizeof(struct shash_desc) + crypto_shash_descsize(alg)`만큼 할당하고 transform을 descriptor에 연결합니다.

`calc_hash()`는 descriptor를 초기화하고 `crypto_shash_digest()`로 input data의 digest를 계산한 뒤 descriptor를 해제합니다. `test_hash()`는 `sha1-padlock-nano` transform을 할당하여 계산을 호출하고 마지막에 `crypto_free_shash()`로 해제합니다.

struct sdesc {
    struct shash_desc shash;
    char ctx[];
};

static struct sdesc *init_sdesc(struct crypto_shash *alg)
{
    struct sdesc *sdesc;
    int size;

    size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
    sdesc = kmalloc(size, GFP_KERNEL);
    if (!sdesc)
        return ERR_PTR(-ENOMEM);
    sdesc->shash.tfm = alg;
    return sdesc;
}

static int calc_hash(struct crypto_shash *alg,
             const unsigned char *data, unsigned int datalen,
             unsigned char *digest)
{
    struct sdesc *sdesc;
    int ret;

    sdesc = init_sdesc(alg);
    if (IS_ERR(sdesc)) {
        pr_info("can't alloc sdesc\n");
        return PTR_ERR(sdesc);
    }

    ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
    kfree(sdesc);
    return ret;
}

static int test_hash(const unsigned char *data, unsigned int datalen,
             unsigned char *digest)
{
    struct crypto_shash *alg;
    char *hash_alg_name = "sha1-padlock-nano";
    int ret;

    alg = crypto_alloc_shash(hash_alg_name, 0, 0);
    if (IS_ERR(alg)) {
            pr_info("can't alloc alg %s\n", hash_alg_name);
            return PTR_ERR(alg);
    }
    ret = calc_hash(alg, data, datalen, digest);
    crypto_free_shash(alg);
    return ret;
}

Random Number Generator 사용 예제

153-187

Random Number Generator 사용 code 예제

`get_random_numbers()`는 output buffer와 length를 검사한 뒤 `crypto_alloc_rng("drbg_nopr_sha256", 0, 0)`로 prediction resistance가 없는 SHA-256 Hash DRBG transform을 할당합니다.

`crypto_rng_get_bytes()`로 요청한 random byte를 채우고 반환값에 따라 실패, data 없음, 반환 byte 수를 기록합니다. 마지막에는 `crypto_free_rng()`로 RNG transform을 해제합니다.

static int get_random_numbers(u8 *buf, unsigned int len)
{
    struct crypto_rng *rng = NULL;
    char *drbg = "drbg_nopr_sha256"; /* Hash DRBG with SHA-256, no PR */
    int ret;

    if (!buf || !len) {
        pr_debug("No output buffer provided\n");
        return -EINVAL;
    }

    rng = crypto_alloc_rng(drbg, 0, 0);
    if (IS_ERR(rng)) {
        pr_debug("could not allocate RNG handle for %s\n", drbg);
        return PTR_ERR(rng);
    }

    ret = crypto_rng_get_bytes(rng, buf, len);
    if (ret < 0)
        pr_debug("generation of random numbers failed\n");
    else if (ret == 0)
        pr_debug("RNG returned no data");
    else
        pr_debug("RNG returned %d bytes of data\n", ret);

out:
    crypto_free_rng(rng);
    return ret;
}