linux/net/mac80211/aes_ccm.c
<<
>>
Prefs
   1/*
   2 * Copyright 2003-2004, Instant802 Networks, Inc.
   3 * Copyright 2005-2006, Devicescape Software, Inc.
   4 *
   5 * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/types.h>
  14#include <linux/err.h>
  15#include <crypto/aead.h>
  16
  17#include <net/mac80211.h>
  18#include "key.h"
  19#include "aes_ccm.h"
  20
  21int ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
  22                              u8 *data, size_t data_len, u8 *mic,
  23                              size_t mic_len)
  24{
  25        struct scatterlist sg[3];
  26        struct aead_request *aead_req;
  27        int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
  28        u8 *__aad;
  29
  30        aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
  31        if (!aead_req)
  32                return -ENOMEM;
  33
  34        __aad = (u8 *)aead_req + reqsize;
  35        memcpy(__aad, aad, CCM_AAD_LEN);
  36
  37        sg_init_table(sg, 3);
  38        sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
  39        sg_set_buf(&sg[1], data, data_len);
  40        sg_set_buf(&sg[2], mic, mic_len);
  41
  42        aead_request_set_tfm(aead_req, tfm);
  43        aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
  44        aead_request_set_ad(aead_req, sg[0].length);
  45
  46        crypto_aead_encrypt(aead_req);
  47        kzfree(aead_req);
  48
  49        return 0;
  50}
  51
  52int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
  53                              u8 *data, size_t data_len, u8 *mic,
  54                              size_t mic_len)
  55{
  56        struct scatterlist sg[3];
  57        struct aead_request *aead_req;
  58        int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
  59        u8 *__aad;
  60        int err;
  61
  62        if (data_len == 0)
  63                return -EINVAL;
  64
  65        aead_req = kzalloc(reqsize + CCM_AAD_LEN, GFP_ATOMIC);
  66        if (!aead_req)
  67                return -ENOMEM;
  68
  69        __aad = (u8 *)aead_req + reqsize;
  70        memcpy(__aad, aad, CCM_AAD_LEN);
  71
  72        sg_init_table(sg, 3);
  73        sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
  74        sg_set_buf(&sg[1], data, data_len);
  75        sg_set_buf(&sg[2], mic, mic_len);
  76
  77        aead_request_set_tfm(aead_req, tfm);
  78        aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
  79        aead_request_set_ad(aead_req, sg[0].length);
  80
  81        err = crypto_aead_decrypt(aead_req);
  82        kzfree(aead_req);
  83
  84        return err;
  85}
  86
  87struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[],
  88                                                    size_t key_len,
  89                                                    size_t mic_len)
  90{
  91        struct crypto_aead *tfm;
  92        int err;
  93
  94        tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC);
  95        if (IS_ERR(tfm))
  96                return tfm;
  97
  98        err = crypto_aead_setkey(tfm, key, key_len);
  99        if (err)
 100                goto free_aead;
 101        err = crypto_aead_setauthsize(tfm, mic_len);
 102        if (err)
 103                goto free_aead;
 104
 105        return tfm;
 106
 107free_aead:
 108        crypto_free_aead(tfm);
 109        return ERR_PTR(err);
 110}
 111
 112void ieee80211_aes_key_free(struct crypto_aead *tfm)
 113{
 114        crypto_free_aead(tfm);
 115}
 116