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