Skip to content

Commit 3daf49a

Browse files
committed
Linux kernel: add chacha20
Signed-off-by: Stephan Mueller <smueller@chronox.de>
1 parent b5b53c0 commit 3daf49a

File tree

7 files changed

+748
-8
lines changed

7 files changed

+748
-8
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Changes 1.7.0-prerelease
2525

2626
* X.509: add lc_x509_policy_cert_subject_match API
2727

28-
* Linux kernel: add support for rfc4106(gcm(aes)), xts(aes), cbc(aes), ctr(aes)
28+
* Linux kernel: add support for rfc4106(gcm(aes)), xts(aes), cbc(aes), ctr(aes), chacha20
2929

3030
Changes 1.6.0
3131
* ASN.1: use stack for small generator for small use cases

linux_kernel/Kbuild.chacha20

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
# Symmetric implementation: ChaCha20
33
leancrypto-$(CONFIG_LEANCRYPTO_CHACHA20) \
44
+= ../sym/src/chacha20.o \
5-
../sym/src/chacha20_selector.o
5+
../sym/src/chacha20_selector.o \
6+
leancrypto_kernel_chacha20.o
7+
8+
obj-m += leancrypto_kernel_chacha20_tester.o
9+
leancrypto_kernel_chacha20_tester-y += ../sym/tests/leancrypto_kernel_chacha20_tester.o
610

711
ifdef CONFIG_X86_64
812
chacha2_avx512_args += -mavx512bw -mavx512dq -mavx512f -mbmi2

linux_kernel/leancrypto_kernel.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,16 @@ static int __init leancrypto_init(void)
221221
if (ret)
222222
goto free_aes_cbc;
223223

224+
ret = lc_kernel_chacha20_init();
225+
if (ret)
226+
goto free_aes_ctr;
227+
224228
out:
225229
return ret;
226230

231+
free_aes_ctr:
232+
lc_kernel_aes_ctr_exit();
233+
227234
free_aes_cbc:
228235
lc_kernel_aes_cbc_exit();
229236

@@ -395,6 +402,7 @@ static void __exit leancrypto_exit(void)
395402
lc_kernel_aes_xts_exit();
396403
lc_kernel_aes_cbc_exit();
397404
lc_kernel_aes_ctr_exit();
405+
lc_kernel_chacha20_exit();
398406

399407
lc_proc_status_show_exit();
400408
}

linux_kernel/leancrypto_kernel.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,20 @@ static inline void lc_kernel_aes_ctr_exit(void)
629629
}
630630
#endif
631631

632+
#ifdef CONFIG_LEANCRYPTO_CHACHA20
633+
int __init lc_kernel_chacha20_init(void);
634+
void lc_kernel_chacha20_exit(void);
635+
#else
636+
static inline int __init lc_kernel_chacha20_init(void)
637+
{
638+
return 0;
639+
}
640+
641+
static inline void lc_kernel_chacha20_exit(void)
642+
{
643+
}
644+
#endif
645+
632646
#ifdef __cplusplus
633647
}
634648
#endif
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
2+
/*
3+
* Copyright (C) 2025, Stephan Mueller <smueller@chronox.de>
4+
*
5+
* License: see LICENSE file in root directory
6+
*
7+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
8+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
9+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
10+
* WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
11+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
12+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
13+
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
14+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
15+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
16+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
17+
* USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
18+
* DAMAGE.
19+
*/
20+
21+
#include <crypto/chacha.h>
22+
#include <crypto/internal/skcipher.h>
23+
#include <crypto/scatterwalk.h>
24+
#include <linux/init.h>
25+
#include <linux/module.h>
26+
#include <linux/types.h>
27+
28+
#include "lc_chacha20.h"
29+
#include "lc_chacha20_private.h"
30+
31+
#include "leancrypto_kernel.h"
32+
33+
static int lc_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
34+
unsigned int keylen)
35+
{
36+
struct lc_sym_ctx *ctx = crypto_skcipher_ctx(tfm);
37+
int err;
38+
39+
err = lc_sym_init(ctx);
40+
if (err)
41+
return err;
42+
43+
return lc_sym_setkey(ctx, key, keylen);
44+
}
45+
46+
static int lc_chacha20_common(struct skcipher_request *req,
47+
void (*crypt_func)(struct lc_sym_ctx *ctx,
48+
const uint8_t *in,
49+
uint8_t *out, size_t len))
50+
{
51+
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
52+
struct lc_sym_ctx *ctx = crypto_skcipher_ctx(tfm);
53+
struct skcipher_walk walk;
54+
int err;
55+
56+
err = lc_sym_setiv(ctx, req->iv, CHACHA_IV_SIZE);
57+
if (err)
58+
return err;
59+
60+
err = skcipher_walk_virt(&walk, req, false);
61+
62+
while (walk.nbytes) {
63+
unsigned int nbytes = walk.nbytes;
64+
65+
if (nbytes < walk.total)
66+
nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);
67+
68+
crypt_func(ctx, walk.src.virt.addr, walk.dst.virt.addr,
69+
nbytes);
70+
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
71+
}
72+
73+
return err;
74+
}
75+
76+
static int lc_chacha20_encrypt(struct skcipher_request *req)
77+
{
78+
return lc_chacha20_common(req, lc_sym_encrypt);
79+
}
80+
81+
static int lc_chacha20_decrypt(struct skcipher_request *req)
82+
{
83+
return lc_chacha20_common(req, lc_sym_decrypt);
84+
}
85+
86+
static int lc_chacha20_init(struct crypto_skcipher *tfm)
87+
{
88+
struct lc_sym_ctx *ctx = crypto_skcipher_ctx(tfm);
89+
90+
LC_SYM_SET_CTX(ctx, lc_chacha20);
91+
92+
return 0;
93+
}
94+
95+
/********************************* Interface *********************************/
96+
97+
static struct skcipher_alg lc_chacha20_skciphers[] = {
98+
{
99+
.base = {
100+
.cra_name = "chacha20",
101+
.cra_driver_name = "chacha20-leancrypto",
102+
.cra_priority = LC_KERNEL_DEFAULT_PRIO,
103+
.cra_blocksize = 1,
104+
.cra_ctxsize = LC_SYM_CTX_SIZE_LEN(LC_CC20_STATE_SIZE),
105+
.cra_alignmask = LC_SYM_COMMON_ALIGNMENT - 1,
106+
.cra_module = THIS_MODULE,
107+
},
108+
.min_keysize = CHACHA_KEY_SIZE,
109+
.max_keysize = CHACHA_KEY_SIZE,
110+
.ivsize = CHACHA_IV_SIZE,
111+
.chunksize = CHACHA_BLOCK_SIZE,
112+
.setkey = lc_chacha20_setkey,
113+
.encrypt = lc_chacha20_encrypt,
114+
.decrypt = lc_chacha20_decrypt,
115+
.init = lc_chacha20_init
116+
}
117+
};
118+
119+
int __init lc_kernel_chacha20_init(void)
120+
{
121+
return crypto_register_skciphers(lc_chacha20_skciphers,
122+
ARRAY_SIZE(lc_chacha20_skciphers));
123+
}
124+
125+
void lc_kernel_chacha20_exit(void)
126+
{
127+
crypto_unregister_skciphers(lc_chacha20_skciphers,
128+
ARRAY_SIZE(lc_chacha20_skciphers));
129+
}

sym/src/chacha20.c

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,14 +317,26 @@ int cc20_setkey(struct lc_sym_state *ctx, const uint8_t *key, size_t keylen)
317317

318318
int cc20_setiv(struct lc_sym_state *ctx, const uint8_t *iv, size_t ivlen)
319319
{
320-
/* IV is counter + nonce */
321-
if (!ctx || ivlen != 12)
320+
if (!ctx)
322321
return -EINVAL;
323322

324-
ctx->counter[0] = 1;
325-
ctx->counter[1] = ptr_to_le32(iv);
326-
ctx->counter[2] = ptr_to_le32(iv + sizeof(uint32_t));
327-
ctx->counter[3] = ptr_to_le32(iv + sizeof(uint32_t) * 2);
323+
/* IV is counter + nonce */
324+
switch (ivlen) {
325+
case 12:
326+
ctx->counter[0] = 1;
327+
ctx->counter[1] = ptr_to_le32(iv);
328+
ctx->counter[2] = ptr_to_le32(iv + sizeof(uint32_t));
329+
ctx->counter[3] = ptr_to_le32(iv + sizeof(uint32_t) * 2);
330+
break;
331+
case 16:
332+
ctx->counter[0] = ptr_to_le32(iv);
333+
ctx->counter[1] = ptr_to_le32(iv + sizeof(uint32_t));
334+
ctx->counter[2] = ptr_to_le32(iv + sizeof(uint32_t) * 2);
335+
ctx->counter[3] = ptr_to_le32(iv + sizeof(uint32_t) * 3);
336+
break;
337+
default:
338+
return -EINVAL;
339+
}
328340

329341
ctx->keystream_ptr = 0;
330342

0 commit comments

Comments
 (0)