1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers 4 * 5 * Copyright (C) 2015 Martin Willi 6 * Copyright (C) 2018 Google LLC 7 */ 8 9 #include <linux/unaligned.h> 10 #include <crypto/algapi.h> 11 #include <crypto/chacha.h> 12 #include <crypto/internal/skcipher.h> 13 #include <linux/module.h> 14 15 struct chacha_ctx { 16 u32 key[8]; 17 int nrounds; 18 }; 19 20 static int chacha_setkey(struct crypto_skcipher *tfm, 21 const u8 *key, unsigned int keysize, int nrounds) 22 { 23 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 24 int i; 25 26 if (keysize != CHACHA_KEY_SIZE) 27 return -EINVAL; 28 29 for (i = 0; i < ARRAY_SIZE(ctx->key); i++) 30 ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32)); 31 32 ctx->nrounds = nrounds; 33 return 0; 34 } 35 36 static int chacha20_setkey(struct crypto_skcipher *tfm, 37 const u8 *key, unsigned int keysize) 38 { 39 return chacha_setkey(tfm, key, keysize, 20); 40 } 41 42 static int chacha12_setkey(struct crypto_skcipher *tfm, 43 const u8 *key, unsigned int keysize) 44 { 45 return chacha_setkey(tfm, key, keysize, 12); 46 } 47 48 static int chacha_stream_xor(struct skcipher_request *req, 49 const struct chacha_ctx *ctx, 50 const u8 iv[CHACHA_IV_SIZE], bool arch) 51 { 52 struct skcipher_walk walk; 53 struct chacha_state state; 54 int err; 55 56 err = skcipher_walk_virt(&walk, req, false); 57 58 chacha_init(&state, ctx->key, iv); 59 60 while (walk.nbytes > 0) { 61 unsigned int nbytes = walk.nbytes; 62 63 if (nbytes < walk.total) 64 nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE); 65 66 if (arch) 67 chacha_crypt(&state, walk.dst.virt.addr, 68 walk.src.virt.addr, nbytes, ctx->nrounds); 69 else 70 chacha_crypt_generic(&state, walk.dst.virt.addr, 71 walk.src.virt.addr, nbytes, 72 ctx->nrounds); 73 err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 74 } 75 76 return err; 77 } 78 79 static int crypto_chacha_crypt_generic(struct skcipher_request *req) 80 { 81 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 82 const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 83 84 return chacha_stream_xor(req, ctx, req->iv, false); 85 } 86 87 static int crypto_chacha_crypt_arch(struct skcipher_request *req) 88 { 89 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 90 const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 91 92 return chacha_stream_xor(req, ctx, req->iv, true); 93 } 94 95 static int crypto_xchacha_crypt(struct skcipher_request *req, bool arch) 96 { 97 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 98 const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 99 struct chacha_ctx subctx; 100 struct chacha_state state; 101 u8 real_iv[16]; 102 103 /* Compute the subkey given the original key and first 128 nonce bits */ 104 chacha_init(&state, ctx->key, req->iv); 105 if (arch) 106 hchacha_block(&state, subctx.key, ctx->nrounds); 107 else 108 hchacha_block_generic(&state, subctx.key, ctx->nrounds); 109 subctx.nrounds = ctx->nrounds; 110 111 /* Build the real IV */ 112 memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */ 113 memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */ 114 115 /* Generate the stream and XOR it with the data */ 116 return chacha_stream_xor(req, &subctx, real_iv, arch); 117 } 118 119 static int crypto_xchacha_crypt_generic(struct skcipher_request *req) 120 { 121 return crypto_xchacha_crypt(req, false); 122 } 123 124 static int crypto_xchacha_crypt_arch(struct skcipher_request *req) 125 { 126 return crypto_xchacha_crypt(req, true); 127 } 128 129 static struct skcipher_alg algs[] = { 130 { 131 .base.cra_name = "chacha20", 132 .base.cra_driver_name = "chacha20-generic", 133 .base.cra_priority = 100, 134 .base.cra_blocksize = 1, 135 .base.cra_ctxsize = sizeof(struct chacha_ctx), 136 .base.cra_module = THIS_MODULE, 137 138 .min_keysize = CHACHA_KEY_SIZE, 139 .max_keysize = CHACHA_KEY_SIZE, 140 .ivsize = CHACHA_IV_SIZE, 141 .chunksize = CHACHA_BLOCK_SIZE, 142 .setkey = chacha20_setkey, 143 .encrypt = crypto_chacha_crypt_generic, 144 .decrypt = crypto_chacha_crypt_generic, 145 }, 146 { 147 .base.cra_name = "xchacha20", 148 .base.cra_driver_name = "xchacha20-generic", 149 .base.cra_priority = 100, 150 .base.cra_blocksize = 1, 151 .base.cra_ctxsize = sizeof(struct chacha_ctx), 152 .base.cra_module = THIS_MODULE, 153 154 .min_keysize = CHACHA_KEY_SIZE, 155 .max_keysize = CHACHA_KEY_SIZE, 156 .ivsize = XCHACHA_IV_SIZE, 157 .chunksize = CHACHA_BLOCK_SIZE, 158 .setkey = chacha20_setkey, 159 .encrypt = crypto_xchacha_crypt_generic, 160 .decrypt = crypto_xchacha_crypt_generic, 161 }, 162 { 163 .base.cra_name = "xchacha12", 164 .base.cra_driver_name = "xchacha12-generic", 165 .base.cra_priority = 100, 166 .base.cra_blocksize = 1, 167 .base.cra_ctxsize = sizeof(struct chacha_ctx), 168 .base.cra_module = THIS_MODULE, 169 170 .min_keysize = CHACHA_KEY_SIZE, 171 .max_keysize = CHACHA_KEY_SIZE, 172 .ivsize = XCHACHA_IV_SIZE, 173 .chunksize = CHACHA_BLOCK_SIZE, 174 .setkey = chacha12_setkey, 175 .encrypt = crypto_xchacha_crypt_generic, 176 .decrypt = crypto_xchacha_crypt_generic, 177 }, 178 { 179 .base.cra_name = "chacha20", 180 .base.cra_driver_name = "chacha20-" __stringify(ARCH), 181 .base.cra_priority = 300, 182 .base.cra_blocksize = 1, 183 .base.cra_ctxsize = sizeof(struct chacha_ctx), 184 .base.cra_module = THIS_MODULE, 185 186 .min_keysize = CHACHA_KEY_SIZE, 187 .max_keysize = CHACHA_KEY_SIZE, 188 .ivsize = CHACHA_IV_SIZE, 189 .chunksize = CHACHA_BLOCK_SIZE, 190 .setkey = chacha20_setkey, 191 .encrypt = crypto_chacha_crypt_arch, 192 .decrypt = crypto_chacha_crypt_arch, 193 }, 194 { 195 .base.cra_name = "xchacha20", 196 .base.cra_driver_name = "xchacha20-" __stringify(ARCH), 197 .base.cra_priority = 300, 198 .base.cra_blocksize = 1, 199 .base.cra_ctxsize = sizeof(struct chacha_ctx), 200 .base.cra_module = THIS_MODULE, 201 202 .min_keysize = CHACHA_KEY_SIZE, 203 .max_keysize = CHACHA_KEY_SIZE, 204 .ivsize = XCHACHA_IV_SIZE, 205 .chunksize = CHACHA_BLOCK_SIZE, 206 .setkey = chacha20_setkey, 207 .encrypt = crypto_xchacha_crypt_arch, 208 .decrypt = crypto_xchacha_crypt_arch, 209 }, 210 { 211 .base.cra_name = "xchacha12", 212 .base.cra_driver_name = "xchacha12-" __stringify(ARCH), 213 .base.cra_priority = 300, 214 .base.cra_blocksize = 1, 215 .base.cra_ctxsize = sizeof(struct chacha_ctx), 216 .base.cra_module = THIS_MODULE, 217 218 .min_keysize = CHACHA_KEY_SIZE, 219 .max_keysize = CHACHA_KEY_SIZE, 220 .ivsize = XCHACHA_IV_SIZE, 221 .chunksize = CHACHA_BLOCK_SIZE, 222 .setkey = chacha12_setkey, 223 .encrypt = crypto_xchacha_crypt_arch, 224 .decrypt = crypto_xchacha_crypt_arch, 225 } 226 }; 227 228 static unsigned int num_algs; 229 230 static int __init crypto_chacha_mod_init(void) 231 { 232 /* register the arch flavours only if they differ from generic */ 233 num_algs = ARRAY_SIZE(algs); 234 BUILD_BUG_ON(ARRAY_SIZE(algs) % 2 != 0); 235 if (!chacha_is_arch_optimized()) 236 num_algs /= 2; 237 238 return crypto_register_skciphers(algs, num_algs); 239 } 240 241 static void __exit crypto_chacha_mod_fini(void) 242 { 243 crypto_unregister_skciphers(algs, num_algs); 244 } 245 246 module_init(crypto_chacha_mod_init); 247 module_exit(crypto_chacha_mod_fini); 248 249 MODULE_LICENSE("GPL"); 250 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); 251 MODULE_DESCRIPTION("Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers"); 252 MODULE_ALIAS_CRYPTO("chacha20"); 253 MODULE_ALIAS_CRYPTO("chacha20-generic"); 254 MODULE_ALIAS_CRYPTO("chacha20-" __stringify(ARCH)); 255 MODULE_ALIAS_CRYPTO("xchacha20"); 256 MODULE_ALIAS_CRYPTO("xchacha20-generic"); 257 MODULE_ALIAS_CRYPTO("xchacha20-" __stringify(ARCH)); 258 MODULE_ALIAS_CRYPTO("xchacha12"); 259 MODULE_ALIAS_CRYPTO("xchacha12-generic"); 260 MODULE_ALIAS_CRYPTO("xchacha12-" __stringify(ARCH)); 261