add new header ident.h
[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 #include <assert.h>\r
26 #include <string.h>\r
27 #include <stdlib.h>\r
28 \r
29 #include "OMAC.h"\r
30 \r
31 OMAC::OMAC() {\r
32     _E = 0;\r
33     block_size = 0;\r
34     t = 0;\r
35     mask = 0;\r
36     ready = 0;\r
37     memset(L, (byte)0, sizeof(L));\r
38     memset(T, (byte)0, sizeof(L));\r
39 }\r
40 \r
41 OMAC::~OMAC() {\r
42     _E = 0;\r
43     block_size = 0;\r
44     t = 0;\r
45     mask = 0;\r
46     ready = 0;\r
47     memset(L, (byte)0, sizeof(L));\r
48     memset(T, (byte)0, sizeof(L));\r
49 }\r
50 \r
51 void OMAC::init(BlockCipher* E) {\r
52     if (E == 0) {\r
53         throw "Invalid block cipher";\r
54     }\r
55     _E = E;\r
56     t = block_size = _E->blockSize();\r
57     if (block_size != 16 && block_size != 8) {\r
58         throw "Block size not supported";\r
59     }\r
60     mask = (block_size == 16) ? 0x87 : 0x1B;\r
61     // compute padding mask:\r
62     memset(L, (byte)0, block_size);\r
63     _E->encrypt(L, L); // L = E_K(0^n)\r
64     uint c = L[0] & 0x80; // carry\r
65     for (uint b = 0; b < block_size - 1; b++) {\r
66         L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));\r
67     }\r
68     L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // B = 2L\r
69     // initialize tag accumulator\r
70     memset(T, (byte)0, block_size);\r
71     ready = 0;\r
72 }\r
73 \r
74 void OMAC::update(const byte* M, uint m) {\r
75     if (_E == 0) {\r
76         throw "OMAC computation not initialized";\r
77     }\r
78     uint i = block_size - t;\r
79     uint j = 0;\r
80     while (m > t) { // N.B. m is strictly larger than t!\r
81         // complete tag block:\r
82         for (uint b = 0; b < t; b++) {\r
83             T[i + b] ^= M[j + b];\r
84         }\r
85         _E->encrypt(T, T); // since there is more data, no padding applies\r
86         // proceed to the next block:\r
87         m -= t;\r
88         j += t;\r
89         t = block_size;\r
90         i = 0;\r
91         //assert(m > 0);\r
92     }\r
93     // process remaining chunk (m bytes):\r
94     for (uint b = 0; b < m; b++) {\r
95         T[i + b] ^= M[j + b];\r
96     }\r
97     t -= m;\r
98     //assert(m == 0 || t < block_size); // m == 0 here only occurs if m == 0 from the very beginning\r
99 }\r
100 \r
101 void OMAC::final(byte* tag) {\r
102     if (_E != 0) {\r
103         // compute padding:\r
104         if (t > 0) {\r
105             // compute special padding mask:\r
106             uint c = L[0] & 0x80; // carry\r
107             for (uint b = 0; b < block_size - 1; b++) {\r
108                 L[b] = (byte)((L[b] << 1) | ((L[b + 1] & 0xff) >> 7));\r
109             }\r
110             L[block_size - 1] = (byte)((L[block_size - 1] << 1) ^ (c != 0 ? mask : 0)); // P = 4L\r
111             // pad incomplete block:\r
112             T[block_size - t] ^= 0x80; // padding toggle\r
113             t = 0;\r
114         }\r
115         for (uint b = 0; b < block_size; b++) {\r
116             T[b] ^= L[b];\r
117         }\r
118         _E->encrypt(T, T); // T contains the complete tag\r
119         ready = 1; // OMAC tag available\r
120         _E = 0; // OMAC computation is complete; context no longer initialized\r
121     } else if (!ready) {\r
122         throw "OMAC computation not initialized";\r
123     }\r
124     memcpy(tag, T, block_size);\r
125 }\r
126 \r