linux/crypto/chacha_generic.c
<<
>>
Prefs
   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 <asm/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
  15static 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
  40static 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
  48static 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
  69static 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
 118static int __init chacha_generic_mod_init(void)
 119{
 120        return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
 121}
 122
 123static void __exit chacha_generic_mod_fini(void)
 124{
 125        crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
 126}
 127
 128subsys_initcall(chacha_generic_mod_init);
 129module_exit(chacha_generic_mod_fini);
 130
 131MODULE_LICENSE("GPL");
 132MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
 133MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)");
 134MODULE_ALIAS_CRYPTO("chacha20");
 135MODULE_ALIAS_CRYPTO("chacha20-generic");
 136MODULE_ALIAS_CRYPTO("xchacha20");
 137MODULE_ALIAS_CRYPTO("xchacha20-generic");
 138MODULE_ALIAS_CRYPTO("xchacha12");
 139MODULE_ALIAS_CRYPTO("xchacha12-generic");
 140