GNU Linux-libre 4.14.303-gnu1
[releases.git] / drivers / staging / ks7010 / michael_mic.c
1 /*
2  *   Driver for KeyStream wireless LAN
3  *
4  *   Copyright (C) 2005-2008 KeyStream Corp.
5  *   Copyright (C) 2009 Renesas Technology Corp.
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/types.h>
13 #include <linux/string.h>
14 #include "michael_mic.h"
15
16 // Rotation functions on 32 bit values
17 #define ROL32(A, n)     (((A) << (n)) | (((A) >> (32 - (n))) & ((1UL << (n)) - 1)))
18 #define ROR32(A, n)     ROL32((A), 32 - (n))
19 // Convert from Byte[] to UInt32 in a portable way
20 #define getUInt32(A, B) ((uint32_t)(A[B + 0] << 0) \
21                 + (A[B + 1] << 8) + (A[B + 2] << 16) + (A[B + 3] << 24))
22
23 // Convert from UInt32 to Byte[] in a portable way
24 #define putUInt32(A, B, C)                                      \
25 do {                                                            \
26         A[B + 0] = (uint8_t)(C & 0xff);                         \
27         A[B + 1] = (uint8_t)((C >> 8) & 0xff);                  \
28         A[B + 2] = (uint8_t)((C >> 16) & 0xff);                 \
29         A[B + 3] = (uint8_t)((C >> 24) & 0xff);                 \
30 } while (0)
31
32 // Reset the state to the empty message.
33 #define MichaelClear(A)                 \
34 do {                                    \
35         A->L = A->K0;                   \
36         A->R = A->K1;                   \
37         A->nBytesInM = 0;               \
38 } while (0)
39
40 static
41 void MichaelInitializeFunction(struct michael_mic_t *Mic, uint8_t *key)
42 {
43         // Set the key
44         Mic->K0 = getUInt32(key, 0);
45         Mic->K1 = getUInt32(key, 4);
46
47         //clear();
48         MichaelClear(Mic);
49 }
50
51 #define MichaelBlockFunction(L, R)                              \
52 do {                                                            \
53         R ^= ROL32(L, 17);                                      \
54         L += R;                                                 \
55         R ^= ((L & 0xff00ff00) >> 8) | ((L & 0x00ff00ff) << 8); \
56         L += R;                                                 \
57         R ^= ROL32(L, 3);                                       \
58         L += R;                                                 \
59         R ^= ROR32(L, 2);                                       \
60         L += R;                                                 \
61 } while (0)
62
63 static
64 void MichaelAppend(struct michael_mic_t *Mic, uint8_t *src, int nBytes)
65 {
66         int addlen;
67
68         if (Mic->nBytesInM) {
69                 addlen = 4 - Mic->nBytesInM;
70                 if (addlen > nBytes)
71                         addlen = nBytes;
72                 memcpy(&Mic->M[Mic->nBytesInM], src, addlen);
73                 Mic->nBytesInM += addlen;
74                 src += addlen;
75                 nBytes -= addlen;
76
77                 if (Mic->nBytesInM < 4)
78                         return;
79
80                 Mic->L ^= getUInt32(Mic->M, 0);
81                 MichaelBlockFunction(Mic->L, Mic->R);
82                 Mic->nBytesInM = 0;
83         }
84
85         while (nBytes >= 4) {
86                 Mic->L ^= getUInt32(src, 0);
87                 MichaelBlockFunction(Mic->L, Mic->R);
88                 src += 4;
89                 nBytes -= 4;
90         }
91
92         if (nBytes > 0) {
93                 Mic->nBytesInM = nBytes;
94                 memcpy(Mic->M, src, nBytes);
95         }
96 }
97
98 static
99 void MichaelGetMIC(struct michael_mic_t *Mic, uint8_t *dst)
100 {
101         u8 *data = Mic->M;
102
103         switch (Mic->nBytesInM) {
104         case 0:
105                 Mic->L ^= 0x5a;
106                 break;
107         case 1:
108                 Mic->L ^= data[0] | 0x5a00;
109                 break;
110         case 2:
111                 Mic->L ^= data[0] | (data[1] << 8) | 0x5a0000;
112                 break;
113         case 3:
114                 Mic->L ^= data[0] | (data[1] << 8) | (data[2] << 16) |
115                     0x5a000000;
116                 break;
117         }
118         MichaelBlockFunction(Mic->L, Mic->R);
119         MichaelBlockFunction(Mic->L, Mic->R);
120         // The appendByte function has already computed the result.
121         putUInt32(dst, 0, Mic->L);
122         putUInt32(dst, 4, Mic->R);
123
124         // Reset to the empty message.
125         MichaelClear(Mic);
126 }
127
128 void MichaelMICFunction(struct michael_mic_t *Mic, u8 *Key,
129                         u8 *Data, int Len, u8 priority,
130                         u8 *Result)
131 {
132         u8 pad_data[4] = { priority, 0, 0, 0 };
133         // Compute the MIC value
134         /*
135          * IEEE802.11i  page 47
136          * Figure 43g TKIP MIC processing format
137          * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
138          * |6 |6 |1       |3 |M   |1 |1 |1 |1 |1 |1 |1 |1 | Octet
139          * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
140          * |DA|SA|Priority|0 |Data|M0|M1|M2|M3|M4|M5|M6|M7|
141          * +--+--+--------+--+----+--+--+--+--+--+--+--+--+
142          */
143         MichaelInitializeFunction(Mic, Key);
144         MichaelAppend(Mic, (uint8_t *)Data, 12);        /* |DA|SA| */
145         MichaelAppend(Mic, pad_data, 4);        /* |Priority|0|0|0| */
146         MichaelAppend(Mic, (uint8_t *)(Data + 12), Len - 12);   /* |Data| */
147         MichaelGetMIC(Mic, Result);
148 }