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