// SPDX-License-Identifier: GPL-2.0 /* * Driver for KeyStream wireless LAN * * Copyright (C) 2005-2008 KeyStream Corp. * Copyright (C) 2009 Renesas Technology Corp. */ #include #include #include #include "michael_mic.h" // Reset the state to the empty message. static inline void michael_clear(struct michael_mic *mic) { mic->l = mic->k0; mic->r = mic->k1; mic->m_bytes = 0; } static void michael_init(struct michael_mic *mic, u8 *key) { // Set the key mic->k0 = get_unaligned_le32(key); mic->k1 = get_unaligned_le32(key + 4); //clear(); michael_clear(mic); } static inline void michael_block(struct michael_mic *mic) { mic->r ^= rol32(mic->l, 17); mic->l += mic->r; mic->r ^= ((mic->l & 0xff00ff00) >> 8) | ((mic->l & 0x00ff00ff) << 8); mic->l += mic->r; mic->r ^= rol32(mic->l, 3); mic->l += mic->r; mic->r ^= ror32(mic->l, 2); mic->l += mic->r; } static void michael_append(struct michael_mic *mic, u8 *src, int bytes) { int addlen; if (mic->m_bytes) { addlen = 4 - mic->m_bytes; if (addlen > bytes) addlen = bytes; memcpy(&mic->m[mic->m_bytes], src, addlen); mic->m_bytes += addlen; src += addlen; bytes -= addlen; if (mic->m_bytes < 4) return; mic->l ^= get_unaligned_le32(mic->m); michael_block(mic); mic->m_bytes = 0; } while (bytes >= 4) { mic->l ^= get_unaligned_le32(src); michael_block(mic); src += 4; bytes -= 4; } if (bytes > 0) { mic->m_bytes = bytes; memcpy(mic->m, src, bytes); } } static void michael_get_mic(struct michael_mic *mic, u8 *dst) { u8 *data = mic->m; switch (mic->m_bytes) { case 0: mic->l ^= 0x5a; break; case 1: mic->l ^= data[0] | 0x5a00; break; case 2: mic->l ^= data[0] | (data[1] << 8) | 0x5a0000; break; case 3: mic->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | 0x5a000000; break; } michael_block(mic); michael_block(mic); // The appendByte function has already computed the result. put_unaligned_le32(mic->l, dst); put_unaligned_le32(mic->r, dst + 4); // Reset to the empty message. michael_clear(mic); } void michael_mic_function(struct michael_mic *mic, u8 *key, u8 *data, unsigned int len, u8 priority, u8 *result) { u8 pad_data[4] = { priority, 0, 0, 0 }; // Compute the MIC value /* * IEEE802.11i page 47 * Figure 43g TKIP MIC processing format * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7| * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ */ michael_init(mic, key); michael_append(mic, data, 12); /* |DA|SA| */ michael_append(mic, pad_data, 4); /* |Priority|0|0|0| */ michael_append(mic, data + 12, len - 12); /* |Data| */ michael_get_mic(mic, result); }