1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * ChaCha and XChaCha stream ciphers, including ChaCha20 (RFC7539) 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 { 18 struct skcipher_walk walk; 19 u32 state[16]; 20 int err; 21 22 err = skcipher_walk_virt(&walk, req, false); 23 24 chacha_init_generic(state, ctx->key, iv); 25 26 while (walk.nbytes > 0) { 27 unsigned int nbytes = walk.nbytes; 28 29 if (nbytes < walk.total) 30 nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE); 31 32 chacha_crypt_generic(state, walk.dst.virt.addr, 33 walk.src.virt.addr, nbytes, ctx->nrounds); 34 err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 35 } 36 37 return err; 38 } 39 40 static int crypto_chacha_crypt(struct skcipher_request *req) 41 { 42 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 43 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 44 45 return chacha_stream_xor(req, ctx, req->iv); 46 } 47 48 static int crypto_xchacha_crypt(struct skcipher_request *req) 49 { 50 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 51 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 52 struct chacha_ctx subctx; 53 u32 state[16]; 54 u8 real_iv[16]; 55 56 /* Compute the subkey given the original key and first 128 nonce bits */ 57 chacha_init_generic(state, ctx->key, req->iv); 58 hchacha_block_generic(state, subctx.key, ctx->nrounds); 59 subctx.nrounds = ctx->nrounds; 60 61 /* Build the real IV */ 62 memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */ 63 memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */ 64 65 /* Generate the stream and XOR it with the data */ 66 return chacha_stream_xor(req, &subctx, real_iv); 67 } 68 69 static struct skcipher_alg algs[] = { 70 { 71 .base.cra_name = "chacha20", 72 .base.cra_driver_name = "chacha20-generic", 73 .base.cra_priority = 100, 74 .base.cra_blocksize = 1, 75 .base.cra_ctxsize = sizeof(struct chacha_ctx), 76 .base.cra_module = THIS_MODULE, 77 78 .min_keysize = CHACHA_KEY_SIZE, 79 .max_keysize = CHACHA_KEY_SIZE, 80 .ivsize = CHACHA_IV_SIZE, 81 .chunksize = CHACHA_BLOCK_SIZE, 82 .setkey = chacha20_setkey, 83 .encrypt = crypto_chacha_crypt, 84 .decrypt = crypto_chacha_crypt, 85 }, { 86 .base.cra_name = "xchacha20", 87 .base.cra_driver_name = "xchacha20-generic", 88 .base.cra_priority = 100, 89 .base.cra_blocksize = 1, 90 .base.cra_ctxsize = sizeof(struct chacha_ctx), 91 .base.cra_module = THIS_MODULE, 92 93 .min_keysize = CHACHA_KEY_SIZE, 94 .max_keysize = CHACHA_KEY_SIZE, 95 .ivsize = XCHACHA_IV_SIZE, 96 .chunksize = CHACHA_BLOCK_SIZE, 97 .setkey = chacha20_setkey, 98 .encrypt = crypto_xchacha_crypt, 99 .decrypt = crypto_xchacha_crypt, 100 }, { 101 .base.cra_name = "xchacha12", 102 .base.cra_driver_name = "xchacha12-generic", 103 .base.cra_priority = 100, 104 .base.cra_blocksize = 1, 105 .base.cra_ctxsize = sizeof(struct chacha_ctx), 106 .base.cra_module = THIS_MODULE, 107 108 .min_keysize = CHACHA_KEY_SIZE, 109 .max_keysize = CHACHA_KEY_SIZE, 110 .ivsize = XCHACHA_IV_SIZE, 111 .chunksize = CHACHA_BLOCK_SIZE, 112 .setkey = chacha12_setkey, 113 .encrypt = crypto_xchacha_crypt, 114 .decrypt = crypto_xchacha_crypt, 115 } 116 }; 117 118 static int __init chacha_generic_mod_init(void) 119 { 120 return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); 121 } 122 123 static void __exit chacha_generic_mod_fini(void) 124 { 125 crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); 126 } 127 128 subsys_initcall(chacha_generic_mod_init); 129 module_exit(chacha_generic_mod_fini); 130 131 MODULE_LICENSE("GPL"); 132 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); 133 MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)"); 134 MODULE_ALIAS_CRYPTO("chacha20"); 135 MODULE_ALIAS_CRYPTO("chacha20-generic"); 136 MODULE_ALIAS_CRYPTO("xchacha20"); 137 MODULE_ALIAS_CRYPTO("xchacha20-generic"); 138 MODULE_ALIAS_CRYPTO("xchacha12"); 139 MODULE_ALIAS_CRYPTO("xchacha12-generic"); 140