Tizen 2.0 Release
[external/libgnutls26.git] / lib / gnutls_hash_int.c
1 /*
2  * Copyright (C) 2000, 2001, 2004, 2005, 2007, 2008, 2010 Free Software
3  * Foundation, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA
23  *
24  */
25
26 /* This file handles all the internal functions that cope with hashes
27  * and HMACs.
28  */
29
30 #include <gnutls_int.h>
31 #include <gnutls_hash_int.h>
32 #include <gnutls_errors.h>
33
34 static int
35 digest_length (gnutls_digest_algorithm_t algo)
36 {
37   switch (algo)
38     {
39     case GNUTLS_DIG_NULL:
40       return 0;
41     case GNUTLS_DIG_MD5:
42     case GNUTLS_DIG_MD2:
43       return 16;
44     case GNUTLS_DIG_SHA1:
45     case GNUTLS_DIG_RMD160:
46       return 20;
47     case GNUTLS_DIG_SHA256:
48       return 32;
49     case GNUTLS_DIG_SHA384:
50       return 48;
51     case GNUTLS_DIG_SHA512:
52       return 64;
53     case GNUTLS_DIG_SHA224:
54       return 28;
55     default:
56       gnutls_assert ();
57       return GNUTLS_E_INTERNAL_ERROR;
58     }
59 }
60
61 int
62 _gnutls_hash_init (digest_hd_st * dig, gnutls_digest_algorithm_t algorithm)
63 {
64   int result;
65   const gnutls_crypto_digest_st *cc = NULL;
66
67   dig->algorithm = algorithm;
68
69   /* check if a digest has been registered 
70    */
71   cc = _gnutls_get_crypto_digest (algorithm);
72   if (cc != NULL)
73     {
74       if (cc->init (algorithm, &dig->handle) < 0)
75         {
76           gnutls_assert ();
77           return GNUTLS_E_HASH_FAILED;
78         }
79
80       dig->hash = cc->hash;
81       dig->copy = cc->copy;
82       dig->output = cc->output;
83       dig->deinit = cc->deinit;
84
85       return 0;
86     }
87
88   result = _gnutls_digest_ops.init (algorithm, &dig->handle);
89   if (result < 0)
90     {
91       gnutls_assert ();
92       return result;
93     }
94
95   dig->hash = _gnutls_digest_ops.hash;
96   dig->copy = _gnutls_digest_ops.copy;
97   dig->output = _gnutls_digest_ops.output;
98   dig->deinit = _gnutls_digest_ops.deinit;
99
100   return 0;
101 }
102
103 /* returns the output size of the given hash/mac algorithm
104  */
105 int
106 _gnutls_hash_get_algo_len (gnutls_digest_algorithm_t algorithm)
107 {
108   return digest_length (algorithm);
109 }
110
111 int
112 _gnutls_hash (digest_hd_st * handle, const void *text, size_t textlen)
113 {
114   if (textlen > 0)
115     {
116       handle->hash (handle->handle, text, textlen);
117     }
118   return 0;
119 }
120
121 int
122 _gnutls_hash_copy (digest_hd_st * dst, digest_hd_st * src)
123 {
124
125   memset (dst, 0, sizeof (*dst));
126   dst->algorithm = src->algorithm;
127
128   dst->hash = src->hash;
129   dst->copy = src->copy;
130   dst->output = src->output;
131   dst->deinit = src->deinit;
132
133   return src->copy (&dst->handle, src->handle);
134 }
135
136 /* when the current output is needed without calling deinit
137  */
138 void
139 _gnutls_hash_output (digest_hd_st * handle, void *digest)
140 {
141   size_t maclen;
142
143   maclen = _gnutls_hash_get_algo_len (handle->algorithm);
144
145   if (digest != NULL)
146     {
147       handle->output (handle->handle, digest, maclen);
148     }
149 }
150
151 void
152 _gnutls_hash_deinit (digest_hd_st * handle, void *digest)
153 {
154   if (handle->handle == NULL)
155     {
156       return;
157     }
158
159   if (digest != NULL)
160     _gnutls_hash_output (handle, digest);
161
162   handle->deinit (handle->handle);
163   handle->handle = NULL;
164 }
165
166 int
167 _gnutls_hash_fast (gnutls_digest_algorithm_t algorithm,
168                    const void *text, size_t textlen, void *digest)
169 {
170   digest_hd_st dig;
171   int ret;
172
173   ret = _gnutls_hash_init (&dig, algorithm);
174   if (ret < 0)
175     {
176       gnutls_assert ();
177       return ret;
178     }
179
180   ret = _gnutls_hash (&dig, text, textlen);
181   if (ret < 0)
182     {
183       gnutls_assert ();
184       _gnutls_hash_deinit (&dig, NULL);
185       return ret;
186     }
187
188   _gnutls_hash_deinit (&dig, digest);
189   return 0;
190 }
191
192
193 /* HMAC interface */
194
195 int
196 _gnutls_hmac_get_algo_len (gnutls_mac_algorithm_t algorithm)
197 {
198   return digest_length (algorithm);
199 }
200
201 int
202 _gnutls_hmac_fast (gnutls_mac_algorithm_t algorithm, const void *key,
203                    int keylen, const void *text, size_t textlen, void *digest)
204 {
205   digest_hd_st dig;
206   int ret;
207
208   ret = _gnutls_hmac_init (&dig, algorithm, key, keylen);
209   if (ret < 0)
210     {
211       gnutls_assert ();
212       return ret;
213     }
214
215   ret = _gnutls_hmac (&dig, text, textlen);
216   if (ret < 0)
217     {
218       gnutls_assert ();
219       _gnutls_hmac_deinit (&dig, NULL);
220       return ret;
221     }
222
223   _gnutls_hmac_deinit (&dig, digest);
224   return 0;
225 }
226
227 int
228 _gnutls_hmac_init (digest_hd_st * dig, gnutls_mac_algorithm_t algorithm,
229                    const void *key, int keylen)
230 {
231   int result;
232   const gnutls_crypto_mac_st *cc = NULL;
233
234   dig->algorithm = algorithm;
235   dig->key = key;
236   dig->keysize = keylen;
237
238   /* check if a digest has been registered 
239    */
240   cc = _gnutls_get_crypto_mac (algorithm);
241   if (cc != NULL)
242     {
243       if (cc->init (algorithm, &dig->handle) < 0)
244         {
245           gnutls_assert ();
246           return GNUTLS_E_HASH_FAILED;
247         }
248
249       if (cc->setkey (dig->handle, key, keylen) < 0)
250         {
251           gnutls_assert ();
252           cc->deinit (dig->handle);
253           return GNUTLS_E_HASH_FAILED;
254         }
255
256       dig->hash = cc->hash;
257       dig->output = cc->output;
258       dig->deinit = cc->deinit;
259
260       return 0;
261     }
262
263   result = _gnutls_mac_ops.init (algorithm, &dig->handle);
264   if (result < 0)
265     {
266       gnutls_assert ();
267       return result;
268     }
269
270   dig->hash = _gnutls_mac_ops.hash;
271   dig->output = _gnutls_mac_ops.output;
272   dig->deinit = _gnutls_mac_ops.deinit;
273
274   if (_gnutls_mac_ops.setkey (dig->handle, key, keylen) < 0)
275     {
276       gnutls_assert();
277       dig->deinit(dig->handle);
278       return GNUTLS_E_HASH_FAILED;
279     }
280
281   return 0;
282 }
283
284 int
285 _gnutls_hmac (digest_hd_st * handle, const void *text, size_t textlen)
286 {
287   if (textlen > 0)
288     {
289       return handle->hash (handle->handle, text, textlen);
290     }
291   return 0;
292 }
293
294 void
295 _gnutls_hmac_output (digest_hd_st * handle, void *digest)
296 {
297   int maclen;
298
299   maclen = _gnutls_hmac_get_algo_len (handle->algorithm);
300
301   if (digest != NULL)
302     {
303       handle->output (handle->handle, digest, maclen);
304     }
305 }
306
307 void
308 _gnutls_hmac_deinit (digest_hd_st * handle, void *digest)
309 {
310   if (handle->handle == NULL)
311     {
312       return;
313     }
314
315   if (digest)
316     _gnutls_hmac_output (handle, digest);
317
318   handle->deinit (handle->handle);
319   handle->handle = NULL;
320 }
321
322 inline static int
323 get_padsize (gnutls_mac_algorithm_t algorithm)
324 {
325   switch (algorithm)
326     {
327     case GNUTLS_MAC_MD5:
328       return 48;
329     case GNUTLS_MAC_SHA1:
330       return 40;
331     default:
332       return 0;
333     }
334 }
335
336
337 /* Special functions for SSL3 MAC
338  */
339
340 int
341 _gnutls_mac_init_ssl3 (digest_hd_st * ret, gnutls_mac_algorithm_t algorithm,
342                        void *key, int keylen)
343 {
344   opaque ipad[48];
345   int padsize, result;
346
347   padsize = get_padsize (algorithm);
348   if (padsize == 0)
349     {
350       gnutls_assert ();
351       return GNUTLS_E_HASH_FAILED;
352     }
353
354   memset (ipad, 0x36, padsize);
355
356   result = _gnutls_hash_init (ret, algorithm);
357   if (result < 0)
358     {
359       gnutls_assert ();
360       return result;
361     }
362
363   ret->key = key;
364   ret->keysize = keylen;
365
366   if (keylen > 0)
367     _gnutls_hash (ret, key, keylen);
368   _gnutls_hash (ret, ipad, padsize);
369
370   return 0;
371 }
372
373 void
374 _gnutls_mac_deinit_ssl3 (digest_hd_st * handle, void *digest)
375 {
376   opaque ret[MAX_HASH_SIZE];
377   digest_hd_st td;
378   opaque opad[48];
379   int padsize;
380   int block, rc;
381
382   padsize = get_padsize (handle->algorithm);
383   if (padsize == 0)
384     {
385       gnutls_assert ();
386       _gnutls_hash_deinit (handle, NULL);
387       return;
388     }
389
390   memset (opad, 0x5C, padsize);
391
392   rc = _gnutls_hash_init (&td, handle->algorithm);
393   if (rc < 0)
394     {
395       gnutls_assert ();
396       _gnutls_hash_deinit (handle, NULL);
397       return;
398     }
399
400   if (handle->keysize > 0)
401     _gnutls_hash (&td, handle->key, handle->keysize);
402
403   _gnutls_hash (&td, opad, padsize);
404   block = _gnutls_hmac_get_algo_len (handle->algorithm);
405   _gnutls_hash_deinit (handle, ret);    /* get the previous hash */
406   _gnutls_hash (&td, ret, block);
407
408   _gnutls_hash_deinit (&td, digest);
409
410   return;
411 }
412
413 void
414 _gnutls_mac_deinit_ssl3_handshake (digest_hd_st * handle,
415                                    void *digest, opaque * key,
416                                    uint32_t key_size)
417 {
418   opaque ret[MAX_HASH_SIZE];
419   digest_hd_st td;
420   opaque opad[48];
421   opaque ipad[48];
422   int padsize;
423   int block, rc;
424
425   padsize = get_padsize (handle->algorithm);
426   if (padsize == 0)
427     {
428       gnutls_assert ();
429       return;
430     }
431
432   memset (opad, 0x5C, padsize);
433   memset (ipad, 0x36, padsize);
434
435   rc = _gnutls_hash_init (&td, handle->algorithm);
436   if (rc < 0)
437     {
438       gnutls_assert ();
439       return;
440     }
441
442   if (key_size > 0)
443     _gnutls_hash (&td, key, key_size);
444
445   _gnutls_hash (&td, opad, padsize);
446   block = _gnutls_hmac_get_algo_len (handle->algorithm);
447
448   if (key_size > 0)
449     _gnutls_hash (handle, key, key_size);
450   _gnutls_hash (handle, ipad, padsize);
451   _gnutls_hash_deinit (handle, ret);    /* get the previous hash */
452
453   _gnutls_hash (&td, ret, block);
454
455   _gnutls_hash_deinit (&td, digest);
456
457   return;
458 }
459
460 static int
461 ssl3_sha (int i, opaque * secret, int secret_len,
462           opaque * rnd, int rnd_len, void *digest)
463 {
464   int j, ret;
465   opaque text1[26];
466
467   digest_hd_st td;
468
469   for (j = 0; j < i + 1; j++)
470     {
471       text1[j] = 65 + i;        /* A==65 */
472     }
473
474   ret = _gnutls_hash_init (&td, GNUTLS_MAC_SHA1);
475   if (ret < 0)
476     {
477       gnutls_assert ();
478       return ret;
479     }
480
481   _gnutls_hash (&td, text1, i + 1);
482   _gnutls_hash (&td, secret, secret_len);
483   _gnutls_hash (&td, rnd, rnd_len);
484
485   _gnutls_hash_deinit (&td, digest);
486   return 0;
487 }
488
489 static int
490 ssl3_md5 (int i, opaque * secret, int secret_len,
491           opaque * rnd, int rnd_len, void *digest)
492 {
493   opaque tmp[MAX_HASH_SIZE];
494   digest_hd_st td;
495   int ret;
496
497   ret = _gnutls_hash_init (&td, GNUTLS_MAC_MD5);
498   if (ret < 0)
499     {
500       gnutls_assert ();
501       return ret;
502     }
503
504   _gnutls_hash (&td, secret, secret_len);
505
506   ret = ssl3_sha (i, secret, secret_len, rnd, rnd_len, tmp);
507   if (ret < 0)
508     {
509       gnutls_assert ();
510       _gnutls_hash_deinit (&td, digest);
511       return ret;
512     }
513
514   _gnutls_hash (&td, tmp, _gnutls_hash_get_algo_len (GNUTLS_MAC_SHA1));
515
516   _gnutls_hash_deinit (&td, digest);
517   return 0;
518 }
519
520 int
521 _gnutls_ssl3_hash_md5 (const void *first, int first_len,
522                        const void *second, int second_len,
523                        int ret_len, opaque * ret)
524 {
525   opaque digest[MAX_HASH_SIZE];
526   digest_hd_st td;
527   int block = _gnutls_hash_get_algo_len (GNUTLS_MAC_MD5);
528   int rc;
529
530   rc = _gnutls_hash_init (&td, GNUTLS_MAC_MD5);
531   if (rc < 0)
532     {
533       gnutls_assert ();
534       return rc;
535     }
536
537   _gnutls_hash (&td, first, first_len);
538   _gnutls_hash (&td, second, second_len);
539
540   _gnutls_hash_deinit (&td, digest);
541
542   if (ret_len > block)
543     {
544       gnutls_assert ();
545       return GNUTLS_E_INTERNAL_ERROR;
546     }
547
548   memcpy (ret, digest, ret_len);
549
550   return 0;
551
552 }
553
554 int
555 _gnutls_ssl3_generate_random (void *secret, int secret_len,
556                               void *rnd, int rnd_len,
557                               int ret_bytes, opaque * ret)
558 {
559   int i = 0, copy, output_bytes;
560   opaque digest[MAX_HASH_SIZE];
561   int block = _gnutls_hash_get_algo_len (GNUTLS_MAC_MD5);
562   int result, times;
563
564   output_bytes = 0;
565   do
566     {
567       output_bytes += block;
568     }
569   while (output_bytes < ret_bytes);
570
571   times = output_bytes / block;
572
573   for (i = 0; i < times; i++)
574     {
575
576       result = ssl3_md5 (i, secret, secret_len, rnd, rnd_len, digest);
577       if (result < 0)
578         {
579           gnutls_assert ();
580           return result;
581         }
582
583       if ((1 + i) * block < ret_bytes)
584         {
585           copy = block;
586         }
587       else
588         {
589           copy = ret_bytes - (i) * block;
590         }
591
592       memcpy (&ret[i * block], digest, copy);
593     }
594
595   return 0;
596 }