import from branch_1_1:
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_psk / OMAC.cpp
1 /*\r
2  * OMAC.cpp\r
3  *\r
4  * The One-key CBC MAC (OMAC) message authentication code,\r
5  * designed by T. Iwata and K. Kurosawa.\r
6  *\r
7  * @author Paulo S. L. M. Barreto\r
8  *\r
9  * @version 2.0\r
10  *\r
11  * This software is hereby placed in the public domain.\r
12  *\r
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS\r
14  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE\r
17  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\r
20  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
22  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
24  */\r
25 \r
26 #include <freeradius-devel/ident.h>\r
27 RCSID("$Id$")\r
28 \r
29 #include <assert.h>\r
30 #include <string.h>\r
31 #include <stdlib.h>\r
32 \r
33 #include "OMAC.h"\r
34 \r
35 OMAC::OMAC() {\r
36     _E = 0;\r
37     block_size = 0;\r
38     t = 0;\r
39     mask = 0;\r
40     ready = 0;\r
41     memset(L, (byte)0, sizeof(L));\r
42     memset(T, (byte)0, sizeof(L));\r
43 }\r
44 \r
45 OMAC::~OMAC() {\r
46     _E = 0;\r
47     block_size = 0;\r
48     t = 0;\r
49     mask = 0;\r
50     ready = 0;\r
51     memset(L, (byte)0, sizeof(L));\r
52     memset(T, (byte)0, sizeof(L));\r
53 }\r
54 \r
55 void OMAC::init(BlockCipher* E) {\r
56     if (E == 0) {\r
57         throw "Invalid block cipher";\r
58     }\r
59     _E = E;\r
60     t = block_size = _E->blockSize();\r
61     if (block_size != 16 && block_size != 8) {\r
62         throw "Block size not supported";\r
63     }\r
64     mask = (block_size == 16) ? 0x87 : 0x1B;\r
65     // compute padding mask:\r
66     memset(L, (byte)0, block_size);\r
67     _E->encrypt(L, L); // L = E_K(0^n)\r
68     uint c = L[0] & 0x80; // carry\r
69     for (uint b = 0; b < block_size - 1; b++) {\r
70         L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));\r
71     }\r
72     L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // B = 2L\r
73     // initialize tag accumulator\r
74     memset(T, (byte)0, block_size);\r
75     ready = 0;\r
76 }\r
77 \r
78 void OMAC::update(const byte* M, uint m) {\r
79     if (_E == 0) {\r
80         throw "OMAC computation not initialized";\r
81     }\r
82     uint i = block_size - t;\r
83     uint j = 0;\r
84     while (m > t) { // N.B. m is strictly larger than t!\r
85         // complete tag block:\r
86         for (uint b = 0; b < t; b++) {\r
87             T[i + b] ^= M[j + b];\r
88         }\r
89         _E->encrypt(T, T); // since there is more data, no padding applies\r
90         // proceed to the next block:\r
91         m -= t;\r
92         j += t;\r
93         t = block_size;\r
94         i = 0;\r
95         //assert(m > 0);\r
96     }\r
97     // process remaining chunk (m bytes):\r
98     for (uint b = 0; b < m; b++) {\r
99         T[i + b] ^= M[j + b];\r
100     }\r
101     t -= m;\r
102     //assert(m == 0 || t < block_size); // m == 0 here only occurs if m == 0 from the very beginning\r
103 }\r
104 \r
105 void OMAC::final(byte* tag) {\r
106     if (_E != 0) {\r
107         // compute padding:\r
108         if (t > 0) {\r
109             // compute special padding mask:\r
110             uint c = L[0] & 0x80; // carry\r
111             for (uint b = 0; b < block_size - 1; b++) {\r
112                 L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));\r
113             }\r
114             L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // P = 4L\r
115             // pad incomplete block:\r
116             T[block_size - t] ^= 0x80; // padding toggle\r
117             t = 0;\r
118         }\r
119         for (uint b = 0; b < block_size; b++) {\r
120             T[b] ^= L[b];\r
121         }\r
122         _E->encrypt(T, T); // T contains the complete tag\r
123         ready = 1; // OMAC tag available\r
124         _E = 0; // OMAC computation is complete; context no longer initialized\r
125     } else if (!ready) {\r
126         throw "OMAC computation not initialized";\r
127     }\r
128     memcpy(tag, T, block_size);\r
129 }\r
130 \r