The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/crypto/michael_mic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Cryptographic API
    3  *
    4  * Michael MIC (IEEE 802.11i/TKIP) keyed digest
    5  *
    6  * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
    7  *
    8  * This program is free software; you can redistribute it and/or modify
    9  * it under the terms of the GNU General Public License version 2 as
   10  * published by the Free Software Foundation.
   11  */
   12 #include <crypto/internal/hash.h>
   13 #include <asm/byteorder.h>
   14 #include <linux/init.h>
   15 #include <linux/module.h>
   16 #include <linux/string.h>
   17 #include <linux/types.h>
   18 
   19 
   20 struct michael_mic_ctx {
   21         u32 l, r;
   22 };
   23 
   24 struct michael_mic_desc_ctx {
   25         u8 pending[4];
   26         size_t pending_len;
   27 
   28         u32 l, r;
   29 };
   30 
   31 static inline u32 xswap(u32 val)
   32 {
   33         return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
   34 }
   35 
   36 
   37 #define michael_block(l, r)     \
   38 do {                            \
   39         r ^= rol32(l, 17);      \
   40         l += r;                 \
   41         r ^= xswap(l);          \
   42         l += r;                 \
   43         r ^= rol32(l, 3);       \
   44         l += r;                 \
   45         r ^= ror32(l, 2);       \
   46         l += r;                 \
   47 } while (0)
   48 
   49 
   50 static int michael_init(struct shash_desc *desc)
   51 {
   52         struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
   53         struct michael_mic_ctx *ctx = crypto_shash_ctx(desc->tfm);
   54         mctx->pending_len = 0;
   55         mctx->l = ctx->l;
   56         mctx->r = ctx->r;
   57 
   58         return 0;
   59 }
   60 
   61 
   62 static int michael_update(struct shash_desc *desc, const u8 *data,
   63                            unsigned int len)
   64 {
   65         struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
   66         const __le32 *src;
   67 
   68         if (mctx->pending_len) {
   69                 int flen = 4 - mctx->pending_len;
   70                 if (flen > len)
   71                         flen = len;
   72                 memcpy(&mctx->pending[mctx->pending_len], data, flen);
   73                 mctx->pending_len += flen;
   74                 data += flen;
   75                 len -= flen;
   76 
   77                 if (mctx->pending_len < 4)
   78                         return 0;
   79 
   80                 src = (const __le32 *)mctx->pending;
   81                 mctx->l ^= le32_to_cpup(src);
   82                 michael_block(mctx->l, mctx->r);
   83                 mctx->pending_len = 0;
   84         }
   85 
   86         src = (const __le32 *)data;
   87 
   88         while (len >= 4) {
   89                 mctx->l ^= le32_to_cpup(src++);
   90                 michael_block(mctx->l, mctx->r);
   91                 len -= 4;
   92         }
   93 
   94         if (len > 0) {
   95                 mctx->pending_len = len;
   96                 memcpy(mctx->pending, src, len);
   97         }
   98 
   99         return 0;
  100 }
  101 
  102 
  103 static int michael_final(struct shash_desc *desc, u8 *out)
  104 {
  105         struct michael_mic_desc_ctx *mctx = shash_desc_ctx(desc);
  106         u8 *data = mctx->pending;
  107         __le32 *dst = (__le32 *)out;
  108 
  109         /* Last block and padding (0x5a, 4..7 x 0) */
  110         switch (mctx->pending_len) {
  111         case 0:
  112                 mctx->l ^= 0x5a;
  113                 break;
  114         case 1:
  115                 mctx->l ^= data[0] | 0x5a00;
  116                 break;
  117         case 2:
  118                 mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
  119                 break;
  120         case 3:
  121                 mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
  122                         0x5a000000;
  123                 break;
  124         }
  125         michael_block(mctx->l, mctx->r);
  126         /* l ^= 0; */
  127         michael_block(mctx->l, mctx->r);
  128 
  129         dst[0] = cpu_to_le32(mctx->l);
  130         dst[1] = cpu_to_le32(mctx->r);
  131 
  132         return 0;
  133 }
  134 
  135 
  136 static int michael_setkey(struct crypto_shash *tfm, const u8 *key,
  137                           unsigned int keylen)
  138 {
  139         struct michael_mic_ctx *mctx = crypto_shash_ctx(tfm);
  140 
  141         const __le32 *data = (const __le32 *)key;
  142 
  143         if (keylen != 8) {
  144                 crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  145                 return -EINVAL;
  146         }
  147 
  148         mctx->l = le32_to_cpu(data[0]);
  149         mctx->r = le32_to_cpu(data[1]);
  150         return 0;
  151 }
  152 
  153 static struct shash_alg alg = {
  154         .digestsize             =       8,
  155         .setkey                 =       michael_setkey,
  156         .init                   =       michael_init,
  157         .update                 =       michael_update,
  158         .final                  =       michael_final,
  159         .descsize               =       sizeof(struct michael_mic_desc_ctx),
  160         .base                   =       {
  161                 .cra_name               =       "michael_mic",
  162                 .cra_blocksize          =       8,
  163                 .cra_alignmask          =       3,
  164                 .cra_ctxsize            =       sizeof(struct michael_mic_ctx),
  165                 .cra_module             =       THIS_MODULE,
  166         }
  167 };
  168 
  169 static int __init michael_mic_init(void)
  170 {
  171         return crypto_register_shash(&alg);
  172 }
  173 
  174 
  175 static void __exit michael_mic_exit(void)
  176 {
  177         crypto_unregister_shash(&alg);
  178 }
  179 
  180 
  181 module_init(michael_mic_init);
  182 module_exit(michael_mic_exit);
  183 
  184 MODULE_LICENSE("GPL v2");
  185 MODULE_DESCRIPTION("Michael MIC");
  186 MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");

Cache object: 69b0b2cd59815618959c413e7f4aa6c1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.