1 // SPDX-License-Identifier: GPL-2.0-only << 2 /* 1 /* 3 * Michael MIC implementation - optimized for 2 * Michael MIC implementation - optimized for TKIP MIC operations 4 * Copyright 2002-2003, Instant802 Networks, I 3 * Copyright 2002-2003, Instant802 Networks, 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. 5 */ 8 */ 6 #include <linux/types.h> 9 #include <linux/types.h> 7 #include <linux/bitops.h> 10 #include <linux/bitops.h> 8 #include <linux/ieee80211.h> 11 #include <linux/ieee80211.h> 9 #include <linux/unaligned.h> !! 12 #include <asm/unaligned.h> 10 13 11 #include "michael.h" 14 #include "michael.h" 12 15 13 static void michael_block(struct michael_mic_c 16 static void michael_block(struct michael_mic_ctx *mctx, u32 val) 14 { 17 { 15 mctx->l ^= val; 18 mctx->l ^= val; 16 mctx->r ^= rol32(mctx->l, 17); 19 mctx->r ^= rol32(mctx->l, 17); 17 mctx->l += mctx->r; 20 mctx->l += mctx->r; 18 mctx->r ^= ((mctx->l & 0xff00ff00) >> 21 mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) | 19 ((mctx->l & 0x00ff00ff) << 22 ((mctx->l & 0x00ff00ff) << 8); 20 mctx->l += mctx->r; 23 mctx->l += mctx->r; 21 mctx->r ^= rol32(mctx->l, 3); 24 mctx->r ^= rol32(mctx->l, 3); 22 mctx->l += mctx->r; 25 mctx->l += mctx->r; 23 mctx->r ^= ror32(mctx->l, 2); 26 mctx->r ^= ror32(mctx->l, 2); 24 mctx->l += mctx->r; 27 mctx->l += mctx->r; 25 } 28 } 26 29 27 static void michael_mic_hdr(struct michael_mic 30 static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key, 28 struct ieee80211_h 31 struct ieee80211_hdr *hdr) 29 { 32 { 30 u8 *da, *sa, tid; 33 u8 *da, *sa, tid; 31 34 32 da = ieee80211_get_DA(hdr); 35 da = ieee80211_get_DA(hdr); 33 sa = ieee80211_get_SA(hdr); 36 sa = ieee80211_get_SA(hdr); 34 if (ieee80211_is_data_qos(hdr->frame_c 37 if (ieee80211_is_data_qos(hdr->frame_control)) 35 tid = ieee80211_get_tid(hdr); !! 38 tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; 36 else 39 else 37 tid = 0; 40 tid = 0; 38 41 39 mctx->l = get_unaligned_le32(key); 42 mctx->l = get_unaligned_le32(key); 40 mctx->r = get_unaligned_le32(key + 4); 43 mctx->r = get_unaligned_le32(key + 4); 41 44 42 /* 45 /* 43 * A pseudo header (DA, SA, Priority, 46 * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC 44 * calculation, but it is _not_ transm 47 * calculation, but it is _not_ transmitted 45 */ 48 */ 46 michael_block(mctx, get_unaligned_le32 49 michael_block(mctx, get_unaligned_le32(da)); 47 michael_block(mctx, get_unaligned_le16 50 michael_block(mctx, get_unaligned_le16(&da[4]) | 48 (get_unaligned_le1 51 (get_unaligned_le16(sa) << 16)); 49 michael_block(mctx, get_unaligned_le32 52 michael_block(mctx, get_unaligned_le32(&sa[2])); 50 michael_block(mctx, tid); 53 michael_block(mctx, tid); 51 } 54 } 52 55 53 void michael_mic(const u8 *key, struct ieee802 56 void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, 54 const u8 *data, size_t data_l 57 const u8 *data, size_t data_len, u8 *mic) 55 { 58 { 56 u32 val; 59 u32 val; 57 size_t block, blocks, left; 60 size_t block, blocks, left; 58 struct michael_mic_ctx mctx; 61 struct michael_mic_ctx mctx; 59 62 60 michael_mic_hdr(&mctx, key, hdr); 63 michael_mic_hdr(&mctx, key, hdr); 61 64 62 /* Real data */ 65 /* Real data */ 63 blocks = data_len / 4; 66 blocks = data_len / 4; 64 left = data_len % 4; 67 left = data_len % 4; 65 68 66 for (block = 0; block < blocks; block+ 69 for (block = 0; block < blocks; block++) 67 michael_block(&mctx, get_unali 70 michael_block(&mctx, get_unaligned_le32(&data[block * 4])); 68 71 69 /* Partial block of 0..3 bytes and pad 72 /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make 70 * total length a multiple of 4. */ 73 * total length a multiple of 4. */ 71 val = 0x5a; 74 val = 0x5a; 72 while (left > 0) { 75 while (left > 0) { 73 val <<= 8; 76 val <<= 8; 74 left--; 77 left--; 75 val |= data[blocks * 4 + left] 78 val |= data[blocks * 4 + left]; 76 } 79 } 77 80 78 michael_block(&mctx, val); 81 michael_block(&mctx, val); 79 michael_block(&mctx, 0); 82 michael_block(&mctx, 0); 80 83 81 put_unaligned_le32(mctx.l, mic); 84 put_unaligned_le32(mctx.l, mic); 82 put_unaligned_le32(mctx.r, mic + 4); 85 put_unaligned_le32(mctx.r, mic + 4); 83 } 86 } 84 87
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.