Commit | Line | Data |
---|---|---|
a0a954b1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
13a9930d WS |
2 | /* |
3 | * Driver for KeyStream wireless LAN | |
4 | * | |
13a9930d WS |
5 | * Copyright (C) 2005-2008 KeyStream Corp. |
6 | * Copyright (C) 2009 Renesas Technology Corp. | |
13a9930d WS |
7 | */ |
8 | ||
8da5b3e7 | 9 | #include <asm/unaligned.h> |
91e77224 SP |
10 | #include <linux/bitops.h> |
11 | #include <linux/string.h> | |
13a9930d WS |
12 | #include "michael_mic.h" |
13 | ||
13a9930d | 14 | |
13a9930d | 15 | // Reset the state to the empty message. |
e5082ba1 | 16 | static inline void michael_clear(struct michael_mic *mic) |
ca0bda15 SP |
17 | { |
18 | mic->l = mic->k0; | |
19 | mic->r = mic->k1; | |
20 | mic->m_bytes = 0; | |
21 | } | |
13a9930d | 22 | |
e5082ba1 | 23 | static void michael_init(struct michael_mic *mic, u8 *key) |
13a9930d WS |
24 | { |
25 | // Set the key | |
f7380a88 SP |
26 | mic->k0 = get_unaligned_le32(key); |
27 | mic->k1 = get_unaligned_le32(key + 4); | |
13a9930d WS |
28 | |
29 | //clear(); | |
ca0bda15 | 30 | michael_clear(mic); |
13a9930d WS |
31 | } |
32 | ||
e5082ba1 | 33 | static inline void michael_block(struct michael_mic *mic) |
c61cc2cc SP |
34 | { |
35 | mic->r ^= rol32(mic->l, 17); | |
36 | mic->l += mic->r; | |
37 | mic->r ^= ((mic->l & 0xff00ff00) >> 8) | | |
38 | ((mic->l & 0x00ff00ff) << 8); | |
39 | mic->l += mic->r; | |
f2052072 | 40 | mic->r ^= rol32(mic->l, 3); |
c61cc2cc | 41 | mic->l += mic->r; |
f2052072 | 42 | mic->r ^= ror32(mic->l, 2); |
c61cc2cc SP |
43 | mic->l += mic->r; |
44 | } | |
13a9930d | 45 | |
e5082ba1 | 46 | static void michael_append(struct michael_mic *mic, u8 *src, int bytes) |
13a9930d | 47 | { |
cab898fb | 48 | int addlen; |
c4b370ef | 49 | |
79955850 SP |
50 | if (mic->m_bytes) { |
51 | addlen = 4 - mic->m_bytes; | |
52 | if (addlen > bytes) | |
53 | addlen = bytes; | |
54 | memcpy(&mic->m[mic->m_bytes], src, addlen); | |
55 | mic->m_bytes += addlen; | |
13a9930d | 56 | src += addlen; |
79955850 | 57 | bytes -= addlen; |
13a9930d | 58 | |
79955850 | 59 | if (mic->m_bytes < 4) |
13a9930d WS |
60 | return; |
61 | ||
f7380a88 | 62 | mic->l ^= get_unaligned_le32(mic->m); |
c61cc2cc | 63 | michael_block(mic); |
79955850 | 64 | mic->m_bytes = 0; |
13a9930d WS |
65 | } |
66 | ||
79955850 | 67 | while (bytes >= 4) { |
f7380a88 | 68 | mic->l ^= get_unaligned_le32(src); |
c61cc2cc | 69 | michael_block(mic); |
13a9930d | 70 | src += 4; |
79955850 | 71 | bytes -= 4; |
13a9930d WS |
72 | } |
73 | ||
79955850 SP |
74 | if (bytes > 0) { |
75 | mic->m_bytes = bytes; | |
76 | memcpy(mic->m, src, bytes); | |
13a9930d WS |
77 | } |
78 | } | |
79 | ||
e5082ba1 | 80 | static void michael_get_mic(struct michael_mic *mic, u8 *dst) |
13a9930d | 81 | { |
9018154f | 82 | u8 *data = mic->m; |
c4b370ef | 83 | |
9018154f | 84 | switch (mic->m_bytes) { |
13a9930d | 85 | case 0: |
9018154f | 86 | mic->l ^= 0x5a; |
13a9930d WS |
87 | break; |
88 | case 1: | |
9018154f | 89 | mic->l ^= data[0] | 0x5a00; |
13a9930d WS |
90 | break; |
91 | case 2: | |
9018154f | 92 | mic->l ^= data[0] | (data[1] << 8) | 0x5a0000; |
13a9930d WS |
93 | break; |
94 | case 3: | |
9018154f | 95 | mic->l ^= data[0] | (data[1] << 8) | (data[2] << 16) | |
cab898fb | 96 | 0x5a000000; |
13a9930d WS |
97 | break; |
98 | } | |
c61cc2cc SP |
99 | michael_block(mic); |
100 | michael_block(mic); | |
13a9930d | 101 | // The appendByte function has already computed the result. |
8da5b3e7 SP |
102 | put_unaligned_le32(mic->l, dst); |
103 | put_unaligned_le32(mic->r, dst + 4); | |
13a9930d WS |
104 | |
105 | // Reset to the empty message. | |
9018154f | 106 | michael_clear(mic); |
13a9930d WS |
107 | } |
108 | ||
e5082ba1 | 109 | void michael_mic_function(struct michael_mic *mic, u8 *key, |
5e5cd808 | 110 | u8 *data, unsigned int len, u8 priority, u8 *result) |
13a9930d | 111 | { |
81710951 | 112 | u8 pad_data[4] = { priority, 0, 0, 0 }; |
13a9930d WS |
113 | // Compute the MIC value |
114 | /* | |
115 | * IEEE802.11i page 47 | |
116 | * Figure 43g TKIP MIC processing format | |
117 | * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ | |
118 | * |6 |6 |1 |3 |M |1 |1 |1 |1 |1 |1 |1 |1 | Octet | |
119 | * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ | |
120 | * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7| | |
121 | * +--+--+--------+--+----+--+--+--+--+--+--+--+--+ | |
122 | */ | |
808a05c0 | 123 | michael_init(mic, key); |
7d89799a | 124 | michael_append(mic, data, 12); /* |DA|SA| */ |
79955850 | 125 | michael_append(mic, pad_data, 4); /* |Priority|0|0|0| */ |
7d89799a | 126 | michael_append(mic, data + 12, len - 12); /* |Data| */ |
9018154f | 127 | michael_get_mic(mic, result); |
13a9930d | 128 | } |