import from branch_1_1:
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_psk / EAX.cpp
1 /*\r
2  * EAX.cpp\r
3  *\r
4  * The EAX authenticated encryption mode of operation,\r
5  * designed by M. Bellare, P. Rogaway and D. Wagner.\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 "EAX.h"\r
34 \r
35 EAX::EAX() {\r
36         _E = 0; // block cipher context\r
37         tag_size = 0;\r
38         block_size = 0;\r
39         t_n = 0;      // [t]_n\r
40         _C = 0;       // CTR context\r
41         nt = 0;\r
42         ht = 0;\r
43         mt = 0;\r
44 }\r
45 \r
46 /*********************************************************************\r
47  * Calls common to incremental and non-incremental API\r
48  ********************************************************************/\r
49 \r
50 void EAX::initialize(const byte* K, uint k, uint t, BlockCipher* E) {\r
51         if (E == 0) {\r
52                 throw "Invalid cipher";\r
53         }\r
54     if (K == 0) {\r
55         throw "Invalid key size";\r
56     }\r
57     if (t > E->blockSize()) {\r
58         throw "Invalid tag size";\r
59     }\r
60     _E = E;\r
61     _E->makeKey(K, k, DIR_ENCRYPT);\r
62     _C = new CTR(_E);\r
63     tag_size = t;\r
64     block_size = _E->blockSize();\r
65     t_n = (byte *)calloc(block_size, 1);\r
66     nt = (byte *)calloc(block_size, 1);\r
67     ht = (byte *)calloc(block_size, 1);\r
68     mt = (byte *)calloc(block_size, 1);\r
69 }\r
70 \r
71 /**\r
72  * Session is over; destroy all key material and cleanup!\r
73  */\r
74 EAX::~EAX() {\r
75         if (_E != 0) {\r
76                 t_n[block_size - 1] = 0;\r
77                 delete _C;\r
78                 memset(nt, (byte)0, block_size);\r
79                 memset(ht, (byte)0, block_size);\r
80                 memset(mt, (byte)0, block_size);\r
81         }\r
82 }\r
83 \r
84 /**\r
85  * Supply a message header. The header "grows" with each call\r
86  * until a eax_provide_header() call is made that follows a\r
87  * eax_encrypt(), eax_decrypt(), eax_provide_plaintext(),\r
88  * eax_provide_ciphertext() or eax_compute_plaintext() call.\r
89  * That starts reinitializes the header.\r
90  */\r
91 void EAX::provideHeader(const byte* H, uint h) {\r
92     if (H == 0 && h > 0) {\r
93         throw "Invalid header";\r
94     }\r
95     _H.update(H, h);\r
96 }\r
97 \r
98 \r
99 /*********************************************************************\r
100  * All-in-one, non-incremental interface\r
101  ********************************************************************/\r
102 \r
103 /**\r
104  * Encrypt the given message with the given key, nonce and header.\r
105  * Specify the header (if nonempty) with eax_provide_header().\r
106  */\r
107 void EAX::encrypt(\r
108         const byte* N,  // the nonce and\r
109         uint n,         // its length (in bytes), and\r
110         const byte* M,  // the plaintext and\r
111         uint m,         // its length (in bytes).\r
112         byte* C,        // The m-byte ciphertext\r
113         byte* T) {      // and the tag T are returned.\r
114     provideNonce(N, n);\r
115     computeCiphertext(M, m, C);\r
116     if (T != 0) {\r
117         computeTag(T);\r
118     }\r
119 }\r
120 \r
121 /**\r
122  * Decrypt the given ciphertext with the given key, nonce and header.\r
123  * Specify the header (if nonempty) with eax_provide_header().\r
124  * Returns 1 for a valid ciphertext, 0 for an invalid ciphertext and for invalid or missing parameters.\r
125  */\r
126 bool EAX::decrypt(\r
127         const byte* N,  // the nonce and\r
128         uint n,         // its length (in bytes), and\r
129         const byte* C,  // the ciphertext and\r
130         uint c,         // its length (in bytes), and\r
131         const byte* T,  // the tag.\r
132         byte* P) {      // if valid, return the c-byte plaintext.\r
133     provideNonce(N, n);\r
134     provideCiphertext(C, c);\r
135     if (checkTag(T)) {\r
136         computePlaintext(C, c, P);\r
137         return true;\r
138     } else {\r
139         return false;\r
140     }\r
141 }\r
142 \r
143 \r
144 /*********************************************************************\r
145  * Incremental interface\r
146  ********************************************************************/\r
147 \r
148 /**\r
149  * Provide a nonce. For encryption, do this before calling\r
150  * eax_compute_ciphertext() and eax_compute_tag();\r
151  * for decryption, do this before calling\r
152  * eax_provide_ciphertext(), eax_check_tag, or eax_compute_plaintext().\r
153  */\r
154 void EAX::provideNonce(const byte* N, uint n) {\r
155     if (N == 0 && n > 0) {\r
156         throw "Invalid nonce";\r
157     }\r
158     // nonce OMAC:\r
159     t_n[block_size - 1] = 0;\r
160     _N.init(_E);\r
161     _N.update(t_n, block_size);\r
162     _N.update(N, n);\r
163     _N.final(nt);\r
164     _C->init(nt); // N <- OMAC_K^0(N)\r
165     memset(nt, (byte)0, block_size);\r
166     // header OMAC:\r
167     t_n[block_size - 1] = 1;\r
168     _H.init(_E);\r
169     _H.update(t_n, block_size);\r
170     // message OMAC:\r
171     t_n[block_size - 1] = 2;\r
172     _M.init(_E);\r
173     _M.update(t_n, block_size);\r
174 }\r
175 \r
176 /**\r
177  * Encrypt a message or a part of a message.\r
178  * The nonce needs already to have been\r
179  * specified by a call to eax_provide_nonce().\r
180  */\r
181 void EAX::computeCiphertext(const byte* M, uint m, byte* C) {\r
182     if (M == 0 && m > 0 ||\r
183         C == 0) {\r
184         throw "Invalid buffer(s)";\r
185     }\r
186     _C->update(M, m, C);\r
187     _M.update(C, m);\r
188 }\r
189 \r
190 /**\r
191  * Message and header finished: compute the authentication tag that is a part\r
192  * of the complete ciphertext.\r
193  */\r
194 void EAX::computeTag(byte* T) {     // compute the tag T.\r
195     if (T == 0 && tag_size > 0) {\r
196         throw "Invalid tag";\r
197     }\r
198     //assert(M.t < block_size);   // at least [t]_n must have been provided\r
199     _N.final(nt);\r
200     _H.final(ht);\r
201     _M.final(mt);\r
202     for (uint i = 0; i < tag_size; i++) {\r
203         T[i] = (byte)(nt[i] ^ ht[i] ^ mt[i]);\r
204     }\r
205 }\r
206 \r
207 /**\r
208  * Supply the ciphertext, or the next piece of ciphertext.\r
209  * This is used to check for the subsequent authenticity check eax_check_tag().\r
210  */\r
211 void EAX::provideCiphertext(const byte* C, uint c) {\r
212     if (C == 0 && c > 0) {\r
213         throw "Invalid ciphertext";\r
214     }\r
215     _M.update(C, c);\r
216 }\r
217 \r
218 /**\r
219  * The nonce, ciphertext and header have all been fully provided; check if\r
220  * they are valid for the given tag.\r
221  * Returns true for a valid ciphertext, false for an invalid ciphertext\r
222  * (in which case plaintext/ciphertext might be zeroized as well).\r
223  */\r
224 bool EAX::checkTag(const byte* T) {\r
225     if (T == 0 && tag_size > 0) {\r
226         throw "Invalid tag";\r
227     }\r
228     //assert(M.t < block_size);   // at least [t]_n must have been provided\r
229     _N.final(nt);\r
230     _H.final(ht);\r
231     _M.final(mt);\r
232     for (uint i = 0; i < tag_size; i++) {\r
233         if (T[i] != (byte)(nt[i] ^ ht[i] ^ mt[i])) {\r
234             return false;\r
235         }\r
236     }\r
237     return true;\r
238 }\r
239 \r
240 /**\r
241  * Recover the plaintext from the provided ciphertext.\r
242  * A call to eax_provide_nonce() needs to precede this call.\r
243  * The caller is responsible for separately checking if the ciphertext is valid.\r
244  * Normally this would be done before computing the plaintext with\r
245  * eax_compute_plaintext().\r
246  */\r
247 void EAX::computePlaintext(const byte* C, uint c, byte* P) {\r
248     if (C == 0 && c > 0 ||\r
249         P == 0) {\r
250         throw "Invalid buffer(s)";\r
251     }\r
252     _C->update(C, c, P);\r
253 }\r
254 \r