use cast in _gnutls_hash_fast
[gnutls:gnutls.git] / lib / x509 / pkcs12_encr.c
1 /* minip12.c - A mini pkcs-12 implementation (modified for gnutls)
2  *
3  * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuTLS.
6  *
7  * The GnuTLS is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>
19  *
20  */
21
22 #include <gnutls_int.h>
23
24 #include <gnutls_mpi.h>
25 #include <gnutls_errors.h>
26 #include <x509_int.h>
27 #include <c-ctype.h>
28 #include <algorithms.h>
29
30 /* Returns 0 if the password is ok, or a negative error
31  * code instead.
32  */
33 static int _pkcs12_check_pass(const char *pass, size_t plen)
34 {
35         unsigned int i;
36
37         for (i = 0; i < plen; i++) {
38                 if (c_isascii(pass[i]))
39                         continue;
40                 return GNUTLS_E_INVALID_PASSWORD;
41         }
42
43         return 0;
44 }
45
46 #define MAX_PASS_LEN 128
47
48 /* ID should be:
49  * 3 for MAC
50  * 2 for IV
51  * 1 for encryption key
52  *
53  * Note that this function produces different key for the
54  * NULL password, and for the password with zero length.
55  */
56 int
57 _gnutls_pkcs12_string_to_key(const mac_entry_st * me,
58                              unsigned int id, const uint8_t * salt,
59                              unsigned int salt_size, unsigned int iter,
60                              const char *pw, unsigned int req_keylen,
61                              uint8_t * keybuf)
62 {
63         int rc;
64         unsigned int i, j;
65         digest_hd_st md;
66         bigint_t num_b1 = NULL, num_ij = NULL;
67         bigint_t mpi512 = NULL;
68         unsigned int pwlen;
69         uint8_t hash[MAX_HASH_SIZE], buf_b[64], buf_i[MAX_PASS_LEN * 2 + 64], *p;
70         uint8_t d[64];
71         size_t cur_keylen;
72         size_t n, m, p_size, i_size;
73         unsigned mac_len;
74         const uint8_t buf_512[] =       /* 2^64 */
75         { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81                 0x00, 0x00, 0x00, 0x00, 0x00
82         };
83
84         cur_keylen = 0;
85
86         if (pw == NULL)
87                 pwlen = 0;
88         else
89                 pwlen = strlen(pw);
90
91         if (pwlen > MAX_PASS_LEN)
92                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
93
94         if (me->block_size != 64)
95                 return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
96
97         if ((rc = _pkcs12_check_pass(pw, pwlen)) < 0) {
98                 gnutls_assert();
99                 return rc;
100         }
101
102         rc = _gnutls_mpi_init_scan(&mpi512, buf_512, sizeof(buf_512));
103         if (rc < 0) {
104                 gnutls_assert();
105                 return rc;
106         }
107
108         /* Store salt and password in BUF_I */
109         p_size = ((pwlen / 64) * 64) + 64;
110
111         if (p_size > sizeof(buf_i) - 64)
112                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
113
114         p = buf_i;
115         for (i = 0; i < 64; i++)
116                 *p++ = salt[i % salt_size];
117         if (pw) {
118                 for (i = j = 0; i < p_size; i += 2) {
119                         *p++ = 0;
120                         *p++ = pw[j];
121                         if (++j > pwlen)        /* Note, that we include the trailing (0) */
122                                 j = 0;
123                 }
124         } else
125                 memset(p, 0, p_size);
126
127         i_size = 64 + p_size;
128         mac_len = _gnutls_mac_get_algo_len(me);
129
130         for (;;) {
131                 rc = _gnutls_hash_init(&md, me);
132                 if (rc < 0) {
133                         gnutls_assert();
134                         goto cleanup;
135                 }
136                 memset(d, id & 0xff, 64);
137                 _gnutls_hash(&md, d, 64);
138                 _gnutls_hash(&md, buf_i, pw ? i_size : 64);
139                 _gnutls_hash_deinit(&md, hash);
140                 for (i = 1; i < iter; i++) {
141                         rc = _gnutls_hash_fast((gnutls_digest_algorithm_t)me->id,
142                                                hash, mac_len, hash);
143                         if (rc < 0) {
144                                 gnutls_assert();
145                                 goto cleanup;
146                         }
147                 }
148                 for (i = 0; i < mac_len && cur_keylen < req_keylen; i++)
149                         keybuf[cur_keylen++] = hash[i];
150                 if (cur_keylen == req_keylen) {
151                         rc = 0; /* ready */
152                         goto cleanup;
153                 }
154
155                 /* need more bytes. */
156                 for (i = 0; i < 64; i++)
157                         buf_b[i] = hash[i % mac_len];
158                 n = 64;
159                 rc = _gnutls_mpi_init_scan(&num_b1, buf_b, n);
160                 if (rc < 0) {
161                         gnutls_assert();
162                         goto cleanup;
163                 }
164
165                 rc = _gnutls_mpi_add_ui(num_b1, num_b1, 1);
166                 if (rc < 0) {
167                         gnutls_assert();
168                         goto cleanup;
169                 }
170                 
171                 for (i = 0; i < 128; i += 64) {
172                         n = 64;
173                         rc = _gnutls_mpi_init_scan(&num_ij, buf_i + i, n);
174                         if (rc < 0) {
175                                 gnutls_assert();
176                                 goto cleanup;
177                         }
178
179                         rc = _gnutls_mpi_addm(num_ij, num_ij, num_b1, mpi512);
180                         if (rc < 0) {
181                                 gnutls_assert();
182                                 goto cleanup;
183                         }
184
185                         n = 64;
186 #ifndef PKCS12_BROKEN_KEYGEN
187                         m = (_gnutls_mpi_get_nbits(num_ij) + 7) / 8;
188 #else
189                         m = n;
190 #endif
191                         memset(buf_i + i, 0, n - m);
192                         rc = _gnutls_mpi_print(num_ij, buf_i + i + n - m,
193                                                &n);
194                         if (rc < 0) {
195                                 gnutls_assert();
196                                 goto cleanup;
197                         }
198                         _gnutls_mpi_release(&num_ij);
199                 }
200         }
201       cleanup:
202         _gnutls_mpi_release(&num_ij);
203         _gnutls_mpi_release(&num_b1);
204         _gnutls_mpi_release(&mpi512);
205
206         return rc;
207 }