1 /* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5
2    Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009, 2010 Free Software
3    Foundation, Inc.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18 
19 /* Written by Simon Josefsson. */
20 
21 // #include <config.h>
22 
23 // #include "gc.h"
24 
25 #include "gc-pbkdf2-sha1.h"
26 #include "hmac.h"
27 
28 #include <string.h>
29 
30 /* Implement PKCS#5 PBKDF2 as per RFC 2898.  The PRF to use is hard
31    coded to be HMAC-SHA1.  Inputs are the password P of length PLEN,
32    the salt S of length SLEN, the iteration counter C (> 0), and the
33    desired derived output length DKLEN.  Output buffer is DK which
34    must have room for at least DKLEN octets.  The output buffer will
35    be filled with the derived data.  */
36 /*Gc_rc*/ int
pbkdf2_sha1(const char * P,size_t Plen,const char * S,size_t Slen,unsigned int c,char * DK,size_t dkLen)37 /*gc_*/pbkdf2_sha1 (const char *P, size_t Plen,
38                 const char *S, size_t Slen,
39                 unsigned int c,
40                 char *DK, size_t dkLen)
41 {
42   unsigned int hLen = 20;
43   char U[20];
44   char T[20];
45   unsigned int u;
46   unsigned int l;
47   unsigned int r;
48   unsigned int i;
49   unsigned int k;
50   int rc;
51   char *tmp;
52   size_t tmplen = Slen + 4;
53 
54   if (c == 0)
55     return /*GC_PKCS5_INVALID_ITERATION_COUNT*/ -1;
56 
57   if (dkLen == 0)
58     return /*GC_PKCS5_INVALID_DERIVED_KEY_LENGTH*/ -1;
59 
60   if (dkLen > 4294967295U)
61     return /*GC_PKCS5_DERIVED_KEY_TOO_LONG*/ -1;
62 
63   l = ((dkLen - 1) / hLen) + 1;
64   r = dkLen - (l - 1) * hLen;
65 
66   tmp = (char*)malloc (tmplen);
67   if (tmp == NULL)
68     return /*GC_MALLOC_ERROR*/ -1;
69 
70   memcpy (tmp, S, Slen);
71 
72   for (i = 1; i <= l; i++)
73     {
74       memset (T, 0, hLen);
75 
76       for (u = 1; u <= c; u++)
77         {
78           if (u == 1)
79             {
80               tmp[Slen + 0] = (i & 0xff000000) >> 24;
81               tmp[Slen + 1] = (i & 0x00ff0000) >> 16;
82               tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
83               tmp[Slen + 3] = (i & 0x000000ff) >> 0;
84 
85               rc = /*gc_*/hmac_sha1 (P, Plen, tmp, tmplen, U);
86             }
87           else
88             rc = /*gc_*/hmac_sha1 (P, Plen, U, hLen, U);
89 
90           if (rc != /*GC_OK*/ 0)
91             {
92               free (tmp);
93               return rc;
94             }
95 
96           for (k = 0; k < hLen; k++)
97             T[k] ^= U[k];
98         }
99 
100       memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
101     }
102 
103   free (tmp);
104 
105   return /*GC_OK*/ 0;
106 }
107