linux/crypto/cmac.c
<<
>>
Prefs
   1/*
   2 * CMAC: Cipher Block Mode for Authentication
   3 *
   4 * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
   5 *
   6 * Based on work by:
   7 *  Copyright © 2013 Tom St Denis <tstdenis@elliptictech.com>
   8 * Based on crypto/xcbc.c:
   9 *  Copyright © 2006 USAGI/WIDE Project,
  10 *   Author: Kazunori Miyazawa <miyazawa@linux-ipv6.org>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 */
  18
  19#include <crypto/internal/hash.h>
  20#include <linux/err.h>
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23
  24/*
  25 * +------------------------
  26 * | <parent tfm>
  27 * +------------------------
  28 * | cmac_tfm_ctx
  29 * +------------------------
  30 * | consts (block size * 2)
  31 * +------------------------
  32 */
  33struct cmac_tfm_ctx {
  34        struct crypto_cipher *child;
  35        u8 ctx[];
  36};
  37
  38/*
  39 * +------------------------
  40 * | <shash desc>
  41 * +------------------------
  42 * | cmac_desc_ctx
  43 * +------------------------
  44 * | odds (block size)
  45 * +------------------------
  46 * | prev (block size)
  47 * +------------------------
  48 */
  49struct cmac_desc_ctx {
  50        unsigned int len;
  51        u8 ctx[];
  52};
  53
  54static int crypto_cmac_digest_setkey(struct crypto_shash *parent,
  55                                     const u8 *inkey, unsigned int keylen)
  56{
  57        unsigned long alignmask = crypto_shash_alignmask(parent);
  58        struct cmac_tfm_ctx *ctx = crypto_shash_ctx(parent);
  59        unsigned int bs = crypto_shash_blocksize(parent);
  60        __be64 *consts = PTR_ALIGN((void *)ctx->ctx, alignmask + 1);
  61        u64 _const[2];
  62        int i, err = 0;
  63        u8 msb_mask, gfmask;
  64
  65        err = crypto_cipher_setkey(ctx->child, inkey, keylen);
  66        if (err)
  67                return err;
  68
  69        /* encrypt the zero block */
  70        memset(consts, 0, bs);
  71        crypto_cipher_encrypt_one(ctx->child, (u8 *)consts, (u8 *)consts);
  72
  73        switch (bs) {
  74        case 16:
  75                gfmask = 0x87;
  76                _const[0] = be64_to_cpu(consts[1]);
  77                _const[1] = be64_to_cpu(consts[0]);
  78
  79                /* gf(2^128) multiply zero-ciphertext with u and u^2 */
  80                for (i = 0; i < 4; i += 2) {
  81                        msb_mask = ((s64)_const[1] >> 63) & gfmask;
  82                        _const[1] = (_const[1] << 1) | (_const[0] >> 63);
  83                        _const[0] = (_const[0] << 1) ^ msb_mask;
  84
  85                        consts[i + 0] = cpu_to_be64(_const[1]);
  86                        consts[i + 1] = cpu_to_be64(_const[0]);
  87                }
  88
  89                break;
  90        case 8:
  91                gfmask = 0x1B;
  92                _const[0] = be64_to_cpu(consts[0]);
  93
  94                /* gf(2^64) multiply zero-ciphertext with u and u^2 */
  95                for (i = 0; i < 2; i++) {
  96                        msb_mask = ((s64)_const[0] >> 63) & gfmask;
  97                        _const[0] = (_const[0] << 1) ^ msb_mask;
  98
  99                        consts[i] = cpu_to_be64(_const[0]);
 100                }
 101
 102                break;
 103        }
 104
 105        return 0;
 106}
 107
 108static int crypto_cmac_digest_init(struct shash_desc *pdesc)
 109{
 110        unsigned long alignmask = crypto_shash_alignmask(pdesc->tfm);
 111        struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
 112        int bs = crypto_shash_blocksize(pdesc->tfm);
 113        u8 *prev = PTR_ALIGN((void *)ctx->ctx, alignmask + 1) + bs;
 114
 115        ctx->len = 0;
 116        memset(prev, 0, bs);
 117
 118        return 0;
 119}
 120
 121static int crypto_cmac_digest_update(struct shash_desc *pdesc, const u8 *p,
 122                                     unsigned int len)
 123{
 124        struct crypto_shash *parent = pdesc->tfm;
 125        unsigned long alignmask = crypto_shash_alignmask(parent);
 126        struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
 127        struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
 128        struct crypto_cipher *tfm = tctx->child;
 129        int bs = crypto_shash_blocksize(parent);
 130        u8 *odds = PTR_ALIGN((void *)ctx->ctx, alignmask + 1);
 131        u8 *prev = odds + bs;
 132
 133        /* checking the data can fill the block */
 134        if ((ctx->len + len) <= bs) {
 135                memcpy(odds + ctx->len, p, len);
 136                ctx->len += len;
 137                return 0;
 138        }
 139
 140        /* filling odds with new data and encrypting it */
 141        memcpy(odds + ctx->len, p, bs - ctx->len);
 142        len -= bs - ctx->len;
 143        p += bs - ctx->len;
 144
 145        crypto_xor(prev, odds, bs);
 146        crypto_cipher_encrypt_one(tfm, prev, prev);
 147
 148        /* clearing the length */
 149        ctx->len = 0;
 150
 151        /* encrypting the rest of data */
 152        while (len > bs) {
 153                crypto_xor(prev, p, bs);
 154                crypto_cipher_encrypt_one(tfm, prev, prev);
 155                p += bs;
 156                len -= bs;
 157        }
 158
 159        /* keeping the surplus of blocksize */
 160        if (len) {
 161                memcpy(odds, p, len);
 162                ctx->len = len;
 163        }
 164
 165        return 0;
 166}
 167
 168static int crypto_cmac_digest_final(struct shash_desc *pdesc, u8 *out)
 169{
 170        struct crypto_shash *parent = pdesc->tfm;
 171        unsigned long alignmask = crypto_shash_alignmask(parent);
 172        struct cmac_tfm_ctx *tctx = crypto_shash_ctx(parent);
 173        struct cmac_desc_ctx *ctx = shash_desc_ctx(pdesc);
 174        struct crypto_cipher *tfm = tctx->child;
 175        int bs = crypto_shash_blocksize(parent);
 176        u8 *consts = PTR_ALIGN((void *)tctx->ctx, alignmask + 1);
 177        u8 *odds = PTR_ALIGN((void *)ctx->ctx, alignmask + 1);
 178        u8 *prev = odds + bs;
 179        unsigned int offset = 0;
 180
 181        if (ctx->len != bs) {
 182                unsigned int rlen;
 183                u8 *p = odds + ctx->len;
 184
 185                *p = 0x80;
 186                p++;
 187
 188                rlen = bs - ctx->len - 1;
 189                if (rlen)
 190                        memset(p, 0, rlen);
 191
 192                offset += bs;
 193        }
 194
 195        crypto_xor(prev, odds, bs);
 196        crypto_xor(prev, consts + offset, bs);
 197
 198        crypto_cipher_encrypt_one(tfm, out, prev);
 199
 200        return 0;
 201}
 202
 203static int cmac_init_tfm(struct crypto_tfm *tfm)
 204{
 205        struct crypto_cipher *cipher;
 206        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 207        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 208        struct cmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
 209
 210        cipher = crypto_spawn_cipher(spawn);
 211        if (IS_ERR(cipher))
 212                return PTR_ERR(cipher);
 213
 214        ctx->child = cipher;
 215
 216        return 0;
 217};
 218
 219static void cmac_exit_tfm(struct crypto_tfm *tfm)
 220{
 221        struct cmac_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
 222        crypto_free_cipher(ctx->child);
 223}
 224
 225static int cmac_create(struct crypto_template *tmpl, struct rtattr **tb)
 226{
 227        struct shash_instance *inst;
 228        struct crypto_alg *alg;
 229        unsigned long alignmask;
 230        int err;
 231
 232        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH);
 233        if (err)
 234                return err;
 235
 236        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
 237                                  CRYPTO_ALG_TYPE_MASK);
 238        if (IS_ERR(alg))
 239                return PTR_ERR(alg);
 240
 241        switch (alg->cra_blocksize) {
 242        case 16:
 243        case 8:
 244                break;
 245        default:
 246                goto out_put_alg;
 247        }
 248
 249        inst = shash_alloc_instance("cmac", alg);
 250        err = PTR_ERR(inst);
 251        if (IS_ERR(inst))
 252                goto out_put_alg;
 253
 254        err = crypto_init_spawn(shash_instance_ctx(inst), alg,
 255                                shash_crypto_instance(inst),
 256                                CRYPTO_ALG_TYPE_MASK);
 257        if (err)
 258                goto out_free_inst;
 259
 260        alignmask = alg->cra_alignmask | (sizeof(long) - 1);
 261        inst->alg.base.cra_alignmask = alignmask;
 262        inst->alg.base.cra_priority = alg->cra_priority;
 263        inst->alg.base.cra_blocksize = alg->cra_blocksize;
 264
 265        inst->alg.digestsize = alg->cra_blocksize;
 266        inst->alg.descsize =
 267                ALIGN(sizeof(struct cmac_desc_ctx), crypto_tfm_ctx_alignment())
 268                + (alignmask & ~(crypto_tfm_ctx_alignment() - 1))
 269                + alg->cra_blocksize * 2;
 270
 271        inst->alg.base.cra_ctxsize =
 272                ALIGN(sizeof(struct cmac_tfm_ctx), alignmask + 1)
 273                + alg->cra_blocksize * 2;
 274
 275        inst->alg.base.cra_init = cmac_init_tfm;
 276        inst->alg.base.cra_exit = cmac_exit_tfm;
 277
 278        inst->alg.init = crypto_cmac_digest_init;
 279        inst->alg.update = crypto_cmac_digest_update;
 280        inst->alg.final = crypto_cmac_digest_final;
 281        inst->alg.setkey = crypto_cmac_digest_setkey;
 282
 283        err = shash_register_instance(tmpl, inst);
 284        if (err) {
 285out_free_inst:
 286                shash_free_instance(shash_crypto_instance(inst));
 287        }
 288
 289out_put_alg:
 290        crypto_mod_put(alg);
 291        return err;
 292}
 293
 294static struct crypto_template crypto_cmac_tmpl = {
 295        .name = "cmac",
 296        .create = cmac_create,
 297        .free = shash_free_instance,
 298        .module = THIS_MODULE,
 299};
 300
 301static int __init crypto_cmac_module_init(void)
 302{
 303        return crypto_register_template(&crypto_cmac_tmpl);
 304}
 305
 306static void __exit crypto_cmac_module_exit(void)
 307{
 308        crypto_unregister_template(&crypto_cmac_tmpl);
 309}
 310
 311module_init(crypto_cmac_module_init);
 312module_exit(crypto_cmac_module_exit);
 313
 314MODULE_LICENSE("GPL");
 315MODULE_DESCRIPTION("CMAC keyed hash algorithm");
 316
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.