Line data Source code
1 : /*
2 : * gnome-keyring
3 : *
4 : * Copyright (C) 2008 Stefan Walter
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see
18 : * <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "config.h"
22 :
23 : #include "egg-padding.h"
24 :
25 : #include <gcrypt.h>
26 :
27 : #include "egg/egg-secure-memory.h"
28 :
29 : /* ----------------------------------------------------------------------------
30 : * INTERNAL
31 : */
32 :
33 : static void
34 1 : fill_random_nonzero (guchar *data, gsize n_data)
35 : {
36 : guchar *rnd;
37 : guint n_zero, i, j;
38 :
39 1 : gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
40 :
41 : /* Find any zeros in random data */
42 1 : n_zero = 0;
43 4 : for (i = 0; i < n_data; ++i) {
44 3 : if (data[i] == 0x00)
45 0 : ++n_zero;
46 : }
47 :
48 1 : while (n_zero > 0) {
49 0 : rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
50 0 : n_zero = 0;
51 0 : for (i = 0, j = 0; i < n_data; ++i) {
52 0 : if (data[i] != 0x00)
53 0 : continue;
54 :
55 : /* Use some of the replacement data */
56 0 : data[i] = rnd[j];
57 0 : ++j;
58 :
59 : /* It's zero again :( */
60 0 : if (data[i] == 0x00)
61 0 : n_zero++;
62 : }
63 :
64 0 : gcry_free (rnd);
65 : }
66 1 : }
67 :
68 : static gboolean
69 10 : unpad_pkcs1 (guchar bt, EggAllocator alloc, gsize block, const guchar* padded,
70 : gsize n_padded, gpointer *raw, gsize *n_raw)
71 : {
72 : const guchar *at;
73 :
74 10 : if (block && n_padded % block != 0)
75 1 : return FALSE;
76 :
77 : /* Check the header */
78 9 : if (padded[0] != 0x00 || padded[1] != bt)
79 2 : return FALSE;
80 :
81 : /* The first zero byte after the header */
82 7 : at = memchr (padded + 2, 0x00, n_padded - 2);
83 7 : if (!at)
84 1 : return FALSE;
85 :
86 6 : if (alloc == NULL)
87 6 : alloc = g_realloc;
88 :
89 6 : ++at;
90 6 : *n_raw = n_padded - (at - padded);
91 6 : if (raw) {
92 3 : *raw = (alloc) (NULL, *n_raw + 1);
93 3 : if (*raw == NULL)
94 0 : return FALSE;
95 3 : memcpy (*raw, at, *n_raw);
96 :
97 : /* Convenience null terminate the result */
98 3 : memset (((guchar*)*raw) + *n_raw, 0, 1);
99 : }
100 :
101 6 : return TRUE;
102 : }
103 :
104 : /* ----------------------------------------------------------------------------
105 : * PUBLIC
106 : */
107 :
108 : gboolean
109 4 : egg_padding_zero_pad (EggAllocator alloc, gsize block, gconstpointer raw,
110 : gsize n_raw, gpointer *padded, gsize *n_padded)
111 : {
112 : guchar *pad;
113 : gsize n_pad;
114 :
115 : /*
116 : * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
117 : * padding data
118 : */
119 :
120 4 : g_return_val_if_fail (block != 0, FALSE);
121 :
122 4 : *n_padded = ((n_raw + (block - 1)) / block) * block;
123 4 : g_assert (n_raw <= *n_padded);
124 4 : n_pad = *n_padded - n_raw;
125 4 : g_assert (n_pad < block);
126 :
127 4 : if (alloc == NULL)
128 4 : alloc = g_realloc;
129 :
130 4 : if (padded) {
131 2 : *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
132 2 : if (pad == NULL)
133 0 : return FALSE;
134 2 : memset (pad, 0x00, n_pad);
135 2 : memcpy (pad + n_pad, raw, n_raw);
136 : }
137 :
138 4 : return TRUE;
139 : }
140 :
141 : gboolean
142 6 : egg_padding_pkcs1_pad_01 (EggAllocator alloc, gsize block, gconstpointer raw,
143 : gsize n_raw, gpointer *padded, gsize *n_padded)
144 : {
145 : guchar *pad;
146 : gsize n_pad;
147 :
148 : /*
149 : * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
150 : * type padding data
151 : */
152 :
153 6 : g_return_val_if_fail (block != 0, FALSE);
154 6 : g_return_val_if_fail (block > 3, FALSE);
155 :
156 6 : *n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
157 6 : g_assert (n_raw <= *n_padded);
158 6 : n_pad = *n_padded - n_raw;
159 6 : g_assert (n_pad <= block);
160 6 : g_assert (n_pad >= 3);
161 :
162 6 : if (alloc == NULL)
163 4 : alloc = g_realloc;
164 :
165 6 : if (padded) {
166 4 : *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
167 4 : if (pad == NULL)
168 0 : return FALSE;
169 4 : pad[0] = 0; /* Prefix */
170 4 : pad[1] = 1; /* Block type */
171 4 : memset (pad + 2, 0xFF, n_pad - 3);
172 4 : pad[n_pad - 1] = 0;
173 4 : memcpy (pad + n_pad, raw, n_raw);
174 : }
175 :
176 6 : return TRUE;
177 : }
178 :
179 : gboolean
180 1 : egg_padding_pkcs1_pad_02 (EggAllocator alloc, gsize block, gconstpointer raw,
181 : gsize n_raw, gpointer *padded, gsize *n_padded)
182 : {
183 : guchar *pad;
184 : gsize n_pad;
185 :
186 : /*
187 : * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
188 : * type padding data
189 : */
190 :
191 1 : g_return_val_if_fail (block != 0, FALSE);
192 1 : g_return_val_if_fail (block > 3, FALSE);
193 :
194 1 : *n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
195 1 : g_assert (n_raw <= *n_padded);
196 1 : n_pad = *n_padded - n_raw;
197 1 : g_assert (n_pad <= block);
198 1 : g_assert (n_pad >= 3);
199 :
200 1 : if (alloc == NULL)
201 1 : alloc = g_realloc;
202 :
203 1 : if (padded) {
204 1 : *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
205 1 : if (pad == NULL)
206 0 : return FALSE;
207 1 : pad[0] = 0; /* Prefix */
208 1 : pad[1] = 2; /* Block type */
209 1 : fill_random_nonzero (pad + 2, n_pad - 3);
210 1 : pad[n_pad - 1] = 0;
211 1 : memcpy (pad + n_pad, raw, n_raw);
212 : }
213 :
214 1 : return TRUE;
215 : }
216 :
217 : gboolean
218 8 : egg_padding_pkcs1_unpad_01 (EggAllocator alloc, gsize block, gconstpointer padded,
219 : gsize n_padded, gpointer *raw, gsize *n_raw)
220 : {
221 8 : return unpad_pkcs1 (0x01, alloc, block, padded, n_padded, raw, n_raw);
222 : }
223 :
224 : gboolean
225 2 : egg_padding_pkcs1_unpad_02 (EggAllocator alloc, gsize block, gconstpointer padded,
226 : gsize n_padded, gpointer *raw, gsize *n_raw)
227 : {
228 2 : return unpad_pkcs1 (0x02, alloc, block, padded, n_padded, raw, n_raw);
229 : }
230 :
231 : gboolean
232 6 : egg_padding_pkcs7_pad (EggAllocator alloc, gsize block, gconstpointer raw,
233 : gsize n_raw, gpointer *padded, gsize *n_padded)
234 : {
235 : guchar *pad;
236 : gsize n_pad;
237 :
238 6 : g_return_val_if_fail (block != 0, FALSE);
239 6 : g_return_val_if_fail (block < 256, FALSE);
240 :
241 6 : *n_padded = ((n_raw + block) / block) * block;
242 6 : g_assert (n_raw < *n_padded);
243 6 : n_pad = *n_padded - n_raw;
244 6 : g_assert (n_pad > 0 && n_pad <= block);
245 :
246 6 : if (alloc == NULL)
247 6 : alloc = g_realloc;
248 :
249 6 : if (padded) {
250 3 : *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
251 3 : if (pad == NULL)
252 0 : return FALSE;
253 3 : memcpy (pad, raw, n_raw);
254 3 : memset (pad + n_raw, n_pad, n_pad);
255 : }
256 :
257 6 : return TRUE;
258 : }
259 :
260 : gboolean
261 11 : egg_padding_pkcs7_unpad (EggAllocator alloc, gsize block, gconstpointer padded,
262 : gsize n_padded, gpointer *raw, gsize *n_raw)
263 : {
264 : const guchar *pad;
265 : gsize n_pad, i;
266 :
267 11 : if (n_padded == 0)
268 0 : return FALSE;
269 :
270 11 : pad = padded;
271 11 : n_pad = pad[n_padded - 1];
272 :
273 : /* Validate the padding */
274 11 : if (n_pad == 0 || n_pad > 256)
275 1 : return FALSE;
276 10 : if (n_pad > n_padded)
277 1 : return FALSE;
278 9 : if (block && n_pad > block)
279 1 : return FALSE;
280 60 : for (i = n_padded - n_pad; i < n_padded; ++i) {
281 53 : if (pad[i] != n_pad)
282 1 : return FALSE;
283 : }
284 :
285 7 : *n_raw = n_padded - n_pad;
286 :
287 7 : if (alloc == NULL)
288 6 : alloc = g_realloc;
289 :
290 7 : if (raw) {
291 4 : *raw = (alloc) (NULL, *n_raw + 1);
292 4 : if (*raw == NULL)
293 0 : return FALSE;
294 :
295 : /* Output the result, null terminated */
296 4 : memcpy (*raw, pad, *n_raw);
297 4 : memset (((guchar*)*raw) + *n_raw, 0, 1);
298 : }
299 :
300 7 : return TRUE;
301 : }
|