Blame view
crypto/chacha20_generic.c
3.53 KB
c08d0e647 crypto: chacha20 ... |
1 2 3 4 5 6 7 8 9 10 |
/* * ChaCha20 256-bit cipher algorithm, RFC7539 * * Copyright (C) 2015 Martin Willi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ |
dbd872a12 crypto: chacha20 ... |
11 |
#include <asm/unaligned.h> |
c08d0e647 crypto: chacha20 ... |
12 |
#include <crypto/algapi.h> |
31d7247da crypto: chacha20 ... |
13 |
#include <crypto/chacha20.h> |
9ae433bc7 crypto: chacha20 ... |
14 15 |
#include <crypto/internal/skcipher.h> #include <linux/module.h> |
c08d0e647 crypto: chacha20 ... |
16 |
|
c08d0e647 crypto: chacha20 ... |
17 18 19 |
static void chacha20_docrypt(u32 *state, u8 *dst, const u8 *src, unsigned int bytes) { |
9f480faec crypto: chacha20 ... |
20 |
u32 stream[CHACHA20_BLOCK_WORDS]; |
c08d0e647 crypto: chacha20 ... |
21 22 23 24 25 26 |
if (dst != src) memcpy(dst, src, bytes); while (bytes >= CHACHA20_BLOCK_SIZE) { chacha20_block(state, stream); |
9f480faec crypto: chacha20 ... |
27 |
crypto_xor(dst, (const u8 *)stream, CHACHA20_BLOCK_SIZE); |
c08d0e647 crypto: chacha20 ... |
28 29 30 31 32 |
bytes -= CHACHA20_BLOCK_SIZE; dst += CHACHA20_BLOCK_SIZE; } if (bytes) { chacha20_block(state, stream); |
9f480faec crypto: chacha20 ... |
33 |
crypto_xor(dst, (const u8 *)stream, bytes); |
c08d0e647 crypto: chacha20 ... |
34 35 |
} } |
31d7247da crypto: chacha20 ... |
36 |
void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv) |
c08d0e647 crypto: chacha20 ... |
37 |
{ |
ecf3220d8 crypto: chacha20 ... |
38 39 40 41 |
state[0] = 0x61707865; /* "expa" */ state[1] = 0x3320646e; /* "nd 3" */ state[2] = 0x79622d32; /* "2-by" */ state[3] = 0x6b206574; /* "te k" */ |
c08d0e647 crypto: chacha20 ... |
42 43 44 45 46 47 48 49 |
state[4] = ctx->key[0]; state[5] = ctx->key[1]; state[6] = ctx->key[2]; state[7] = ctx->key[3]; state[8] = ctx->key[4]; state[9] = ctx->key[5]; state[10] = ctx->key[6]; state[11] = ctx->key[7]; |
dbd872a12 crypto: chacha20 ... |
50 51 52 53 |
state[12] = get_unaligned_le32(iv + 0); state[13] = get_unaligned_le32(iv + 4); state[14] = get_unaligned_le32(iv + 8); state[15] = get_unaligned_le32(iv + 12); |
c08d0e647 crypto: chacha20 ... |
54 |
} |
31d7247da crypto: chacha20 ... |
55 |
EXPORT_SYMBOL_GPL(crypto_chacha20_init); |
c08d0e647 crypto: chacha20 ... |
56 |
|
9ae433bc7 crypto: chacha20 ... |
57 |
int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key, |
c08d0e647 crypto: chacha20 ... |
58 59 |
unsigned int keysize) { |
9ae433bc7 crypto: chacha20 ... |
60 |
struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm); |
c08d0e647 crypto: chacha20 ... |
61 62 63 64 65 66 |
int i; if (keysize != CHACHA20_KEY_SIZE) return -EINVAL; for (i = 0; i < ARRAY_SIZE(ctx->key); i++) |
dbd872a12 crypto: chacha20 ... |
67 |
ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32)); |
c08d0e647 crypto: chacha20 ... |
68 69 70 |
return 0; } |
31d7247da crypto: chacha20 ... |
71 |
EXPORT_SYMBOL_GPL(crypto_chacha20_setkey); |
c08d0e647 crypto: chacha20 ... |
72 |
|
9ae433bc7 crypto: chacha20 ... |
73 |
int crypto_chacha20_crypt(struct skcipher_request *req) |
c08d0e647 crypto: chacha20 ... |
74 |
{ |
9ae433bc7 crypto: chacha20 ... |
75 76 77 |
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm); struct skcipher_walk walk; |
c08d0e647 crypto: chacha20 ... |
78 79 |
u32 state[16]; int err; |
9ae433bc7 crypto: chacha20 ... |
80 |
err = skcipher_walk_virt(&walk, req, true); |
c08d0e647 crypto: chacha20 ... |
81 |
|
9ae433bc7 crypto: chacha20 ... |
82 |
crypto_chacha20_init(state, ctx, walk.iv); |
c08d0e647 crypto: chacha20 ... |
83 |
|
9ae433bc7 crypto: chacha20 ... |
84 |
while (walk.nbytes > 0) { |
4de437265 crypto: chacha20 ... |
85 86 87 88 |
unsigned int nbytes = walk.nbytes; if (nbytes < walk.total) nbytes = round_down(nbytes, walk.stride); |
c08d0e647 crypto: chacha20 ... |
89 |
chacha20_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr, |
4de437265 crypto: chacha20 ... |
90 91 |
nbytes); err = skcipher_walk_done(&walk, walk.nbytes - nbytes); |
c08d0e647 crypto: chacha20 ... |
92 93 94 95 |
} return err; } |
31d7247da crypto: chacha20 ... |
96 |
EXPORT_SYMBOL_GPL(crypto_chacha20_crypt); |
c08d0e647 crypto: chacha20 ... |
97 |
|
9ae433bc7 crypto: chacha20 ... |
98 99 100 101 102 103 |
static struct skcipher_alg alg = { .base.cra_name = "chacha20", .base.cra_driver_name = "chacha20-generic", .base.cra_priority = 100, .base.cra_blocksize = 1, .base.cra_ctxsize = sizeof(struct chacha20_ctx), |
9ae433bc7 crypto: chacha20 ... |
104 105 106 107 108 109 110 111 112 |
.base.cra_module = THIS_MODULE, .min_keysize = CHACHA20_KEY_SIZE, .max_keysize = CHACHA20_KEY_SIZE, .ivsize = CHACHA20_IV_SIZE, .chunksize = CHACHA20_BLOCK_SIZE, .setkey = crypto_chacha20_setkey, .encrypt = crypto_chacha20_crypt, .decrypt = crypto_chacha20_crypt, |
c08d0e647 crypto: chacha20 ... |
113 114 115 116 |
}; static int __init chacha20_generic_mod_init(void) { |
9ae433bc7 crypto: chacha20 ... |
117 |
return crypto_register_skcipher(&alg); |
c08d0e647 crypto: chacha20 ... |
118 119 120 121 |
} static void __exit chacha20_generic_mod_fini(void) { |
9ae433bc7 crypto: chacha20 ... |
122 |
crypto_unregister_skcipher(&alg); |
c08d0e647 crypto: chacha20 ... |
123 124 125 126 127 128 129 130 131 132 |
} module_init(chacha20_generic_mod_init); module_exit(chacha20_generic_mod_fini); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); MODULE_DESCRIPTION("chacha20 cipher algorithm"); MODULE_ALIAS_CRYPTO("chacha20"); MODULE_ALIAS_CRYPTO("chacha20-generic"); |