linux/crypto/salsa20_generic.c
<<
>>
Prefs
   1/*
   2 * Salsa20: Salsa20 stream cipher algorithm
   3 *
   4 * Copyright (c) 2007 Tan Swee Heng <thesweeheng@gmail.com>
   5 *
   6 * Derived from:
   7 * - salsa20.c: Public domain C code by Daniel J. Bernstein <djb@cr.yp.to>
   8 *
   9 * Salsa20 is a stream cipher candidate in eSTREAM, the ECRYPT Stream
  10 * Cipher Project. It is designed by Daniel J. Bernstein <djb@cr.yp.to>.
  11 * More information about eSTREAM and Salsa20 can be found here:
  12 *   http://www.ecrypt.eu.org/stream/
  13 *   http://cr.yp.to/snuffle.html
  14 *
  15 * This program is free software; you can redistribute it and/or modify it
  16 * under the terms of the GNU General Public License as published by the Free
  17 * Software Foundation; either version 2 of the License, or (at your option)
  18 * any later version.
  19 *
  20 */
  21
  22#include <linux/init.h>
  23#include <linux/module.h>
  24#include <linux/errno.h>
  25#include <linux/crypto.h>
  26#include <linux/types.h>
  27#include <linux/bitops.h>
  28#include <crypto/algapi.h>
  29#include <asm/byteorder.h>
  30
  31#define SALSA20_IV_SIZE        8U
  32#define SALSA20_MIN_KEY_SIZE  16U
  33#define SALSA20_MAX_KEY_SIZE  32U
  34
  35/*
  36 * Start of code taken from D. J. Bernstein's reference implementation.
  37 * With some modifications and optimizations made to suit our needs.
  38 */
  39
  40/*
  41salsa20-ref.c version 20051118
  42D. J. Bernstein
  43Public domain.
  44*/
  45
  46#define U32TO8_LITTLE(p, v) \
  47        { (p)[0] = (v >>  0) & 0xff; (p)[1] = (v >>  8) & 0xff; \
  48          (p)[2] = (v >> 16) & 0xff; (p)[3] = (v >> 24) & 0xff; }
  49#define U8TO32_LITTLE(p)   \
  50        (((u32)((p)[0])      ) | ((u32)((p)[1]) <<  8) | \
  51         ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24)   )
  52
  53struct salsa20_ctx
  54{
  55        u32 input[16];
  56};
  57
  58static void salsa20_wordtobyte(u8 output[64], const u32 input[16])
  59{
  60        u32 x[16];
  61        int i;
  62
  63        memcpy(x, input, sizeof(x));
  64        for (i = 20; i > 0; i -= 2) {
  65                x[ 4] ^= rol32((x[ 0] + x[12]),  7);
  66                x[ 8] ^= rol32((x[ 4] + x[ 0]),  9);
  67                x[12] ^= rol32((x[ 8] + x[ 4]), 13);
  68                x[ 0] ^= rol32((x[12] + x[ 8]), 18);
  69                x[ 9] ^= rol32((x[ 5] + x[ 1]),  7);
  70                x[13] ^= rol32((x[ 9] + x[ 5]),  9);
  71                x[ 1] ^= rol32((x[13] + x[ 9]), 13);
  72                x[ 5] ^= rol32((x[ 1] + x[13]), 18);
  73                x[14] ^= rol32((x[10] + x[ 6]),  7);
  74                x[ 2] ^= rol32((x[14] + x[10]),  9);
  75                x[ 6] ^= rol32((x[ 2] + x[14]), 13);
  76                x[10] ^= rol32((x[ 6] + x[ 2]), 18);
  77                x[ 3] ^= rol32((x[15] + x[11]),  7);
  78                x[ 7] ^= rol32((x[ 3] + x[15]),  9);
  79                x[11] ^= rol32((x[ 7] + x[ 3]), 13);
  80                x[15] ^= rol32((x[11] + x[ 7]), 18);
  81                x[ 1] ^= rol32((x[ 0] + x[ 3]),  7);
  82                x[ 2] ^= rol32((x[ 1] + x[ 0]),  9);
  83                x[ 3] ^= rol32((x[ 2] + x[ 1]), 13);
  84                x[ 0] ^= rol32((x[ 3] + x[ 2]), 18);
  85                x[ 6] ^= rol32((x[ 5] + x[ 4]),  7);
  86                x[ 7] ^= rol32((x[ 6] + x[ 5]),  9);
  87                x[ 4] ^= rol32((x[ 7] + x[ 6]), 13);
  88                x[ 5] ^= rol32((x[ 4] + x[ 7]), 18);
  89                x[11] ^= rol32((x[10] + x[ 9]),  7);
  90                x[ 8] ^= rol32((x[11] + x[10]),  9);
  91                x[ 9] ^= rol32((x[ 8] + x[11]), 13);
  92                x[10] ^= rol32((x[ 9] + x[ 8]), 18);
  93                x[12] ^= rol32((x[15] + x[14]),  7);
  94                x[13] ^= rol32((x[12] + x[15]),  9);
  95                x[14] ^= rol32((x[13] + x[12]), 13);
  96                x[15] ^= rol32((x[14] + x[13]), 18);
  97        }
  98        for (i = 0; i < 16; ++i)
  99                x[i] += input[i];
 100        for (i = 0; i < 16; ++i)
 101                U32TO8_LITTLE(output + 4 * i,x[i]);
 102}
 103
 104static const char sigma[16] = "expand 32-byte k";
 105static const char tau[16] = "expand 16-byte k";
 106
 107static void salsa20_keysetup(struct salsa20_ctx *ctx, const u8 *k, u32 kbytes)
 108{
 109        const char *constants;
 110
 111        ctx->input[1] = U8TO32_LITTLE(k + 0);
 112        ctx->input[2] = U8TO32_LITTLE(k + 4);
 113        ctx->input[3] = U8TO32_LITTLE(k + 8);
 114        ctx->input[4] = U8TO32_LITTLE(k + 12);
 115        if (kbytes == 32) { /* recommended */
 116                k += 16;
 117                constants = sigma;
 118        } else { /* kbytes == 16 */
 119                constants = tau;
 120        }
 121        ctx->input[11] = U8TO32_LITTLE(k + 0);
 122        ctx->input[12] = U8TO32_LITTLE(k + 4);
 123        ctx->input[13] = U8TO32_LITTLE(k + 8);
 124        ctx->input[14] = U8TO32_LITTLE(k + 12);
 125        ctx->input[0] = U8TO32_LITTLE(constants + 0);
 126        ctx->input[5] = U8TO32_LITTLE(constants + 4);
 127        ctx->input[10] = U8TO32_LITTLE(constants + 8);
 128        ctx->input[15] = U8TO32_LITTLE(constants + 12);
 129}
 130
 131static void salsa20_ivsetup(struct salsa20_ctx *ctx, const u8 *iv)
 132{
 133        ctx->input[6] = U8TO32_LITTLE(iv + 0);
 134        ctx->input[7] = U8TO32_LITTLE(iv + 4);
 135        ctx->input[8] = 0;
 136        ctx->input[9] = 0;
 137}
 138
 139static void salsa20_encrypt_bytes(struct salsa20_ctx *ctx, u8 *dst,
 140                                  const u8 *src, unsigned int bytes)
 141{
 142        u8 buf[64];
 143
 144        if (dst != src)
 145                memcpy(dst, src, bytes);
 146
 147        while (bytes) {
 148                salsa20_wordtobyte(buf, ctx->input);
 149
 150                ctx->input[8]++;
 151                if (!ctx->input[8])
 152                        ctx->input[9]++;
 153
 154                if (bytes <= 64) {
 155                        crypto_xor(dst, buf, bytes);
 156                        return;
 157                }
 158
 159                crypto_xor(dst, buf, 64);
 160                bytes -= 64;
 161                dst += 64;
 162        }
 163}
 164
 165/*
 166 * End of code taken from D. J. Bernstein's reference implementation.
 167 */
 168
 169static int setkey(struct crypto_tfm *tfm, const u8 *key,
 170                  unsigned int keysize)
 171{
 172        struct salsa20_ctx *ctx = crypto_tfm_ctx(tfm);
 173        salsa20_keysetup(ctx, key, keysize);
 174        return 0;
 175}
 176
 177static int encrypt(struct blkcipher_desc *desc,
 178                   struct scatterlist *dst, struct scatterlist *src,
 179                   unsigned int nbytes)
 180{
 181        struct blkcipher_walk walk;
 182        struct crypto_blkcipher *tfm = desc->tfm;
 183        struct salsa20_ctx *ctx = crypto_blkcipher_ctx(tfm);
 184        int err;
 185
 186        blkcipher_walk_init(&walk, dst, src, nbytes);
 187        err = blkcipher_walk_virt_block(desc, &walk, 64);
 188
 189        salsa20_ivsetup(ctx, walk.iv);
 190
 191        if (likely(walk.nbytes == nbytes))
 192        {
 193                salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
 194                                      walk.src.virt.addr, nbytes);
 195                return blkcipher_walk_done(desc, &walk, 0);
 196        }
 197
 198        while (walk.nbytes >= 64) {
 199                salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
 200                                      walk.src.virt.addr,
 201                                      walk.nbytes - (walk.nbytes % 64));
 202                err = blkcipher_walk_done(desc, &walk, walk.nbytes % 64);
 203        }
 204
 205        if (walk.nbytes) {
 206                salsa20_encrypt_bytes(ctx, walk.dst.virt.addr,
 207                                      walk.src.virt.addr, walk.nbytes);
 208                err = blkcipher_walk_done(desc, &walk, 0);
 209        }
 210
 211        return err;
 212}
 213
 214static struct crypto_alg alg = {
 215        .cra_name           =   "salsa20",
 216        .cra_driver_name    =   "salsa20-generic",
 217        .cra_priority       =   100,
 218        .cra_flags          =   CRYPTO_ALG_TYPE_BLKCIPHER,
 219        .cra_type           =   &crypto_blkcipher_type,
 220        .cra_blocksize      =   1,
 221        .cra_ctxsize        =   sizeof(struct salsa20_ctx),
 222        .cra_alignmask      =   3,
 223        .cra_module         =   THIS_MODULE,
 224        .cra_u              =   {
 225                .blkcipher = {
 226                        .setkey         =   setkey,
 227                        .encrypt        =   encrypt,
 228                        .decrypt        =   encrypt,
 229                        .min_keysize    =   SALSA20_MIN_KEY_SIZE,
 230                        .max_keysize    =   SALSA20_MAX_KEY_SIZE,
 231                        .ivsize         =   SALSA20_IV_SIZE,
 232                }
 233        }
 234};
 235
 236static int __init salsa20_generic_mod_init(void)
 237{
 238        return crypto_register_alg(&alg);
 239}
 240
 241static void __exit salsa20_generic_mod_fini(void)
 242{
 243        crypto_unregister_alg(&alg);
 244}
 245
 246module_init(salsa20_generic_mod_init);
 247module_exit(salsa20_generic_mod_fini);
 248
 249MODULE_LICENSE("GPL");
 250MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm");
 251MODULE_ALIAS("salsa20");
 252