mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 17:41:44 +00:00
6c2bb98bc3
Up until now algorithms have been happy to get a context pointer since they know everything that's in the tfm already (e.g., alignment, block size). However, once we have parameterised algorithms, such information will be specific to each tfm. So the algorithm API needs to be changed to pass the tfm structure instead of the context pointer. This patch is basically a text substitution. The only tricky bit is the assembly routines that need to get the context pointer offset through asm-offsets.h. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
178 lines
3.5 KiB
C
178 lines
3.5 KiB
C
/*
|
|
* Cryptographic API
|
|
*
|
|
* Michael MIC (IEEE 802.11i/TKIP) keyed digest
|
|
*
|
|
* Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <asm/byteorder.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
#include <linux/crypto.h>
|
|
#include <linux/types.h>
|
|
|
|
|
|
struct michael_mic_ctx {
|
|
u8 pending[4];
|
|
size_t pending_len;
|
|
|
|
u32 l, r;
|
|
};
|
|
|
|
|
|
static inline u32 xswap(u32 val)
|
|
{
|
|
return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
|
|
}
|
|
|
|
|
|
#define michael_block(l, r) \
|
|
do { \
|
|
r ^= rol32(l, 17); \
|
|
l += r; \
|
|
r ^= xswap(l); \
|
|
l += r; \
|
|
r ^= rol32(l, 3); \
|
|
l += r; \
|
|
r ^= ror32(l, 2); \
|
|
l += r; \
|
|
} while (0)
|
|
|
|
|
|
static void michael_init(struct crypto_tfm *tfm)
|
|
{
|
|
struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
|
|
mctx->pending_len = 0;
|
|
}
|
|
|
|
|
|
static void michael_update(struct crypto_tfm *tfm, const u8 *data,
|
|
unsigned int len)
|
|
{
|
|
struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
|
|
const __le32 *src;
|
|
|
|
if (mctx->pending_len) {
|
|
int flen = 4 - mctx->pending_len;
|
|
if (flen > len)
|
|
flen = len;
|
|
memcpy(&mctx->pending[mctx->pending_len], data, flen);
|
|
mctx->pending_len += flen;
|
|
data += flen;
|
|
len -= flen;
|
|
|
|
if (mctx->pending_len < 4)
|
|
return;
|
|
|
|
src = (const __le32 *)mctx->pending;
|
|
mctx->l ^= le32_to_cpup(src);
|
|
michael_block(mctx->l, mctx->r);
|
|
mctx->pending_len = 0;
|
|
}
|
|
|
|
src = (const __le32 *)data;
|
|
|
|
while (len >= 4) {
|
|
mctx->l ^= le32_to_cpup(src++);
|
|
michael_block(mctx->l, mctx->r);
|
|
len -= 4;
|
|
}
|
|
|
|
if (len > 0) {
|
|
mctx->pending_len = len;
|
|
memcpy(mctx->pending, src, len);
|
|
}
|
|
}
|
|
|
|
|
|
static void michael_final(struct crypto_tfm *tfm, u8 *out)
|
|
{
|
|
struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
|
|
u8 *data = mctx->pending;
|
|
__le32 *dst = (__le32 *)out;
|
|
|
|
/* Last block and padding (0x5a, 4..7 x 0) */
|
|
switch (mctx->pending_len) {
|
|
case 0:
|
|
mctx->l ^= 0x5a;
|
|
break;
|
|
case 1:
|
|
mctx->l ^= data[0] | 0x5a00;
|
|
break;
|
|
case 2:
|
|
mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
|
|
break;
|
|
case 3:
|
|
mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
|
|
0x5a000000;
|
|
break;
|
|
}
|
|
michael_block(mctx->l, mctx->r);
|
|
/* l ^= 0; */
|
|
michael_block(mctx->l, mctx->r);
|
|
|
|
dst[0] = cpu_to_le32(mctx->l);
|
|
dst[1] = cpu_to_le32(mctx->r);
|
|
}
|
|
|
|
|
|
static int michael_setkey(struct crypto_tfm *tfm, const u8 *key,
|
|
unsigned int keylen, u32 *flags)
|
|
{
|
|
struct michael_mic_ctx *mctx = crypto_tfm_ctx(tfm);
|
|
const __le32 *data = (const __le32 *)key;
|
|
|
|
if (keylen != 8) {
|
|
if (flags)
|
|
*flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
|
|
return -EINVAL;
|
|
}
|
|
|
|
mctx->l = le32_to_cpu(data[0]);
|
|
mctx->r = le32_to_cpu(data[1]);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static struct crypto_alg michael_mic_alg = {
|
|
.cra_name = "michael_mic",
|
|
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
|
|
.cra_blocksize = 8,
|
|
.cra_ctxsize = sizeof(struct michael_mic_ctx),
|
|
.cra_module = THIS_MODULE,
|
|
.cra_alignmask = 3,
|
|
.cra_list = LIST_HEAD_INIT(michael_mic_alg.cra_list),
|
|
.cra_u = { .digest = {
|
|
.dia_digestsize = 8,
|
|
.dia_init = michael_init,
|
|
.dia_update = michael_update,
|
|
.dia_final = michael_final,
|
|
.dia_setkey = michael_setkey } }
|
|
};
|
|
|
|
|
|
static int __init michael_mic_init(void)
|
|
{
|
|
return crypto_register_alg(&michael_mic_alg);
|
|
}
|
|
|
|
|
|
static void __exit michael_mic_exit(void)
|
|
{
|
|
crypto_unregister_alg(&michael_mic_alg);
|
|
}
|
|
|
|
|
|
module_init(michael_mic_init);
|
|
module_exit(michael_mic_exit);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("Michael MIC");
|
|
MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
|