1 /*
2  * ChaCha20 256-bit cipher algorithm, RFC7539
3  *
4  * Copyright (C) 2015 Martin Willi
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 
12 #include <crypto/algapi.h>
13 #include <linux/crypto.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <crypto/chacha20.h>
17 
rotl32(u32 v,u8 n)18 static inline u32 rotl32(u32 v, u8 n)
19 {
20 	return (v << n) | (v >> (sizeof(v) * 8 - n));
21 }
22 
le32_to_cpuvp(const void * p)23 static inline u32 le32_to_cpuvp(const void *p)
24 {
25 	return le32_to_cpup(p);
26 }
27 
chacha20_block(u32 * state,void * stream)28 static void chacha20_block(u32 *state, void *stream)
29 {
30 	u32 x[16], *out = stream;
31 	int i;
32 
33 	for (i = 0; i < ARRAY_SIZE(x); i++)
34 		x[i] = state[i];
35 
36 	for (i = 0; i < 20; i += 2) {
37 		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],  16);
38 		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],  16);
39 		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],  16);
40 		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],  16);
41 
42 		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],  12);
43 		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],  12);
44 		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10], 12);
45 		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11], 12);
46 
47 		x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],   8);
48 		x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],   8);
49 		x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],   8);
50 		x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],   8);
51 
52 		x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],   7);
53 		x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],   7);
54 		x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10],  7);
55 		x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11],  7);
56 
57 		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],  16);
58 		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],  16);
59 		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],  16);
60 		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],  16);
61 
62 		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10], 12);
63 		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11], 12);
64 		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],  12);
65 		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],  12);
66 
67 		x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],   8);
68 		x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],   8);
69 		x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],   8);
70 		x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],   8);
71 
72 		x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10],  7);
73 		x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11],  7);
74 		x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],   7);
75 		x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],   7);
76 	}
77 
78 	for (i = 0; i < ARRAY_SIZE(x); i++)
79 		out[i] = cpu_to_le32(x[i] + state[i]);
80 
81 	state[12]++;
82 }
83 
chacha20_docrypt(u32 * state,u8 * dst,const u8 * src,unsigned int bytes)84 static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src,
85 			     unsigned int bytes)
86 {
87 	u8 stream[CHACHA20_BLOCK_SIZE];
88 
89 	if (dst != src)
90 		memcpy(dst, src, bytes);
91 
92 	while (bytes >= CHACHA20_BLOCK_SIZE) {
93 		chacha20_block(state, stream);
94 		crypto_xor(dst, stream, CHACHA20_BLOCK_SIZE);
95 		bytes -= CHACHA20_BLOCK_SIZE;
96 		dst += CHACHA20_BLOCK_SIZE;
97 	}
98 	if (bytes) {
99 		chacha20_block(state, stream);
100 		crypto_xor(dst, stream, bytes);
101 	}
102 }
103 
crypto_chacha20_init(u32 * state,struct chacha20_ctx * ctx,u8 * iv)104 void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv)
105 {
106 	static const char constant[16] = "expand 32-byte k";
107 
108 	state[0]  = le32_to_cpuvp(constant +  0);
109 	state[1]  = le32_to_cpuvp(constant +  4);
110 	state[2]  = le32_to_cpuvp(constant +  8);
111 	state[3]  = le32_to_cpuvp(constant + 12);
112 	state[4]  = ctx->key[0];
113 	state[5]  = ctx->key[1];
114 	state[6]  = ctx->key[2];
115 	state[7]  = ctx->key[3];
116 	state[8]  = ctx->key[4];
117 	state[9]  = ctx->key[5];
118 	state[10] = ctx->key[6];
119 	state[11] = ctx->key[7];
120 	state[12] = le32_to_cpuvp(iv +  0);
121 	state[13] = le32_to_cpuvp(iv +  4);
122 	state[14] = le32_to_cpuvp(iv +  8);
123 	state[15] = le32_to_cpuvp(iv + 12);
124 }
125 EXPORT_SYMBOL_GPL(crypto_chacha20_init);
126 
crypto_chacha20_setkey(struct crypto_tfm * tfm,const u8 * key,unsigned int keysize)127 int crypto_chacha20_setkey(struct crypto_tfm *tfm, const u8 *key,
128 			   unsigned int keysize)
129 {
130 	struct chacha20_ctx *ctx = crypto_tfm_ctx(tfm);
131 	int i;
132 
133 	if (keysize != CHACHA20_KEY_SIZE)
134 		return -EINVAL;
135 
136 	for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
137 		ctx->key[i] = le32_to_cpuvp(key + i * sizeof(u32));
138 
139 	return 0;
140 }
141 EXPORT_SYMBOL_GPL(crypto_chacha20_setkey);
142 
crypto_chacha20_crypt(struct blkcipher_desc * desc,struct scatterlist * dst,struct scatterlist * src,unsigned int nbytes)143 int crypto_chacha20_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
144 			  struct scatterlist *src, unsigned int nbytes)
145 {
146 	struct blkcipher_walk walk;
147 	u32 state[16];
148 	int err;
149 
150 	blkcipher_walk_init(&walk, dst, src, nbytes);
151 	err = blkcipher_walk_virt_block(desc, &walk, CHACHA20_BLOCK_SIZE);
152 
153 	crypto_chacha20_init(state, crypto_blkcipher_ctx(desc->tfm), walk.iv);
154 
155 	while (walk.nbytes >= CHACHA20_BLOCK_SIZE) {
156 		chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
157 				 rounddown(walk.nbytes, CHACHA20_BLOCK_SIZE));
158 		err = blkcipher_walk_done(desc, &walk,
159 					  walk.nbytes % CHACHA20_BLOCK_SIZE);
160 	}
161 
162 	if (walk.nbytes) {
163 		chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
164 				 walk.nbytes);
165 		err = blkcipher_walk_done(desc, &walk, 0);
166 	}
167 
168 	return err;
169 }
170 EXPORT_SYMBOL_GPL(crypto_chacha20_crypt);
171 
172 static struct crypto_alg alg = {
173 	.cra_name		= "chacha20",
174 	.cra_driver_name	= "chacha20-generic",
175 	.cra_priority		= 100,
176 	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
177 	.cra_blocksize		= 1,
178 	.cra_type		= &crypto_blkcipher_type,
179 	.cra_ctxsize		= sizeof(struct chacha20_ctx),
180 	.cra_alignmask		= sizeof(u32) - 1,
181 	.cra_module		= THIS_MODULE,
182 	.cra_u			= {
183 		.blkcipher = {
184 			.min_keysize	= CHACHA20_KEY_SIZE,
185 			.max_keysize	= CHACHA20_KEY_SIZE,
186 			.ivsize		= CHACHA20_IV_SIZE,
187 			.geniv		= "seqiv",
188 			.setkey		= crypto_chacha20_setkey,
189 			.encrypt	= crypto_chacha20_crypt,
190 			.decrypt	= crypto_chacha20_crypt,
191 		},
192 	},
193 };
194 
chacha20_generic_mod_init(void)195 static int __init chacha20_generic_mod_init(void)
196 {
197 	return crypto_register_alg(&alg);
198 }
199 
chacha20_generic_mod_fini(void)200 static void __exit chacha20_generic_mod_fini(void)
201 {
202 	crypto_unregister_alg(&alg);
203 }
204 
205 module_init(chacha20_generic_mod_init);
206 module_exit(chacha20_generic_mod_fini);
207 
208 MODULE_LICENSE("GPL");
209 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
210 MODULE_DESCRIPTION("chacha20 cipher algorithm");
211 MODULE_ALIAS_CRYPTO("chacha20");
212 MODULE_ALIAS_CRYPTO("chacha20-generic");
213