Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.7-rc2 150 lines 3.5 kB view raw
1/* 2 * Copyright 2003-2004, Instant802 Networks, Inc. 3 * Copyright 2005-2006, Devicescape Software, Inc. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10#include <linux/kernel.h> 11#include <linux/types.h> 12#include <linux/crypto.h> 13#include <linux/err.h> 14#include <crypto/aes.h> 15 16#include <net/mac80211.h> 17#include "key.h" 18#include "aes_ccm.h" 19 20static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *scratch, u8 *a) 21{ 22 int i; 23 u8 *b_0, *aad, *b, *s_0; 24 25 b_0 = scratch + 3 * AES_BLOCK_SIZE; 26 aad = scratch + 4 * AES_BLOCK_SIZE; 27 b = scratch; 28 s_0 = scratch + AES_BLOCK_SIZE; 29 30 crypto_cipher_encrypt_one(tfm, b, b_0); 31 32 /* Extra Authenticate-only data (always two AES blocks) */ 33 for (i = 0; i < AES_BLOCK_SIZE; i++) 34 aad[i] ^= b[i]; 35 crypto_cipher_encrypt_one(tfm, b, aad); 36 37 aad += AES_BLOCK_SIZE; 38 39 for (i = 0; i < AES_BLOCK_SIZE; i++) 40 aad[i] ^= b[i]; 41 crypto_cipher_encrypt_one(tfm, a, aad); 42 43 /* Mask out bits from auth-only-b_0 */ 44 b_0[0] &= 0x07; 45 46 /* S_0 is used to encrypt T (= MIC) */ 47 b_0[14] = 0; 48 b_0[15] = 0; 49 crypto_cipher_encrypt_one(tfm, s_0, b_0); 50} 51 52 53void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, 54 u8 *data, size_t data_len, 55 u8 *cdata, u8 *mic) 56{ 57 int i, j, last_len, num_blocks; 58 u8 *pos, *cpos, *b, *s_0, *e, *b_0; 59 60 b = scratch; 61 s_0 = scratch + AES_BLOCK_SIZE; 62 e = scratch + 2 * AES_BLOCK_SIZE; 63 b_0 = scratch + 3 * AES_BLOCK_SIZE; 64 65 num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); 66 last_len = data_len % AES_BLOCK_SIZE; 67 aes_ccm_prepare(tfm, scratch, b); 68 69 /* Process payload blocks */ 70 pos = data; 71 cpos = cdata; 72 for (j = 1; j <= num_blocks; j++) { 73 int blen = (j == num_blocks && last_len) ? 74 last_len : AES_BLOCK_SIZE; 75 76 /* Authentication followed by encryption */ 77 for (i = 0; i < blen; i++) 78 b[i] ^= pos[i]; 79 crypto_cipher_encrypt_one(tfm, b, b); 80 81 b_0[14] = (j >> 8) & 0xff; 82 b_0[15] = j & 0xff; 83 crypto_cipher_encrypt_one(tfm, e, b_0); 84 for (i = 0; i < blen; i++) 85 *cpos++ = *pos++ ^ e[i]; 86 } 87 88 for (i = 0; i < CCMP_MIC_LEN; i++) 89 mic[i] = b[i] ^ s_0[i]; 90} 91 92 93int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, 94 u8 *cdata, size_t data_len, u8 *mic, u8 *data) 95{ 96 int i, j, last_len, num_blocks; 97 u8 *pos, *cpos, *b, *s_0, *a, *b_0; 98 99 b = scratch; 100 s_0 = scratch + AES_BLOCK_SIZE; 101 a = scratch + 2 * AES_BLOCK_SIZE; 102 b_0 = scratch + 3 * AES_BLOCK_SIZE; 103 104 num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); 105 last_len = data_len % AES_BLOCK_SIZE; 106 aes_ccm_prepare(tfm, scratch, a); 107 108 /* Process payload blocks */ 109 cpos = cdata; 110 pos = data; 111 for (j = 1; j <= num_blocks; j++) { 112 int blen = (j == num_blocks && last_len) ? 113 last_len : AES_BLOCK_SIZE; 114 115 /* Decryption followed by authentication */ 116 b_0[14] = (j >> 8) & 0xff; 117 b_0[15] = j & 0xff; 118 crypto_cipher_encrypt_one(tfm, b, b_0); 119 for (i = 0; i < blen; i++) { 120 *pos = *cpos++ ^ b[i]; 121 a[i] ^= *pos++; 122 } 123 crypto_cipher_encrypt_one(tfm, a, a); 124 } 125 126 for (i = 0; i < CCMP_MIC_LEN; i++) { 127 if ((mic[i] ^ s_0[i]) != a[i]) 128 return -1; 129 } 130 131 return 0; 132} 133 134 135struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[]) 136{ 137 struct crypto_cipher *tfm; 138 139 tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); 140 if (!IS_ERR(tfm)) 141 crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN); 142 143 return tfm; 144} 145 146 147void ieee80211_aes_key_free(struct crypto_cipher *tfm) 148{ 149 crypto_free_cipher(tfm); 150}