Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * pgp-s2k.c
3 : : * OpenPGP string2key functions.
4 : : *
5 : : * Copyright (c) 2005 Marko Kreen
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : : * SUCH DAMAGE.
28 : : *
29 : : * contrib/pgcrypto/pgp-s2k.c
30 : : */
31 : :
32 : : #include "postgres.h"
33 : :
34 : : #include "pgp.h"
35 : : #include "px.h"
36 : :
37 : : static int
5421 bruce@momjian.us 38 :CBC 5 : calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
39 : : unsigned key_len)
40 : : {
41 : : unsigned md_rlen;
42 : : uint8 buf[PGP_MAX_DIGEST];
43 : : unsigned preload;
44 : : unsigned remain;
6853 45 : 5 : uint8 *dst = s2k->key;
46 : :
47 : 5 : md_rlen = px_md_result_size(md);
48 : :
49 : 5 : remain = s2k->key_len;
50 : 5 : preload = 0;
51 [ + + ]: 12 : while (remain > 0)
52 : : {
53 : 7 : px_md_reset(md);
54 : :
55 [ + + ]: 7 : if (preload)
56 : : {
57 : 2 : memset(buf, 0, preload);
58 : 2 : px_md_update(md, buf, preload);
59 : : }
60 : 7 : preload++;
61 : :
62 : 7 : px_md_update(md, key, key_len);
63 : 7 : px_md_finish(md, buf);
64 : :
65 [ + + ]: 7 : if (remain > md_rlen)
66 : : {
67 : 2 : memcpy(dst, buf, md_rlen);
68 : 2 : dst += md_rlen;
69 : 2 : remain -= md_rlen;
70 : : }
71 : : else
72 : : {
73 : 5 : memcpy(dst, buf, remain);
74 : 5 : remain = 0;
75 : : }
76 : : }
3650 77 : 5 : px_memset(buf, 0, sizeof(buf));
6853 78 : 5 : return 0;
79 : : }
80 : :
81 : : static int
5421 82 : 5 : calc_s2k_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len)
83 : : {
84 : : unsigned md_rlen;
85 : : uint8 buf[PGP_MAX_DIGEST];
6853 86 : 5 : unsigned preload = 0;
87 : : uint8 *dst;
88 : : unsigned remain;
89 : :
90 : 5 : md_rlen = px_md_result_size(md);
91 : :
92 : 5 : dst = s2k->key;
93 : 5 : remain = s2k->key_len;
94 [ + + ]: 12 : while (remain > 0)
95 : : {
96 : 7 : px_md_reset(md);
97 : :
98 [ + + ]: 7 : if (preload > 0)
99 : : {
100 : 2 : memset(buf, 0, preload);
101 : 2 : px_md_update(md, buf, preload);
102 : : }
103 : 7 : preload++;
104 : :
105 : 7 : px_md_update(md, s2k->salt, PGP_S2K_SALT);
106 : 7 : px_md_update(md, key, key_len);
107 : 7 : px_md_finish(md, buf);
108 : :
109 [ + + ]: 7 : if (remain > md_rlen)
110 : : {
111 : 2 : memcpy(dst, buf, md_rlen);
112 : 2 : remain -= md_rlen;
113 : 2 : dst += md_rlen;
114 : : }
115 : : else
116 : : {
117 : 5 : memcpy(dst, buf, remain);
118 : 5 : remain = 0;
119 : : }
120 : : }
3650 121 : 5 : px_memset(buf, 0, sizeof(buf));
6853 122 : 5 : return 0;
123 : : }
124 : :
125 : : static int
5421 126 : 83 : calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
127 : : unsigned key_len)
128 : : {
129 : : unsigned md_rlen;
130 : : uint8 buf[PGP_MAX_DIGEST];
131 : : uint8 *dst;
6853 132 : 83 : unsigned preload = 0;
133 : : unsigned remain,
134 : : c,
135 : : curcnt,
136 : : count;
137 : :
2958 alvherre@alvh.no-ip. 138 : 83 : count = s2k_decode_count(s2k->iter);
139 : :
6853 bruce@momjian.us 140 : 83 : md_rlen = px_md_result_size(md);
141 : :
142 : 83 : remain = s2k->key_len;
143 : 83 : dst = s2k->key;
144 [ + + ]: 179 : while (remain > 0)
145 : : {
146 : 96 : px_md_reset(md);
147 : :
148 [ + + ]: 96 : if (preload)
149 : : {
150 : 13 : memset(buf, 0, preload);
151 : 13 : px_md_update(md, buf, preload);
152 : : }
153 : 96 : preload++;
154 : :
155 : 96 : px_md_update(md, s2k->salt, PGP_S2K_SALT);
156 : 96 : px_md_update(md, key, key_len);
157 : 96 : curcnt = PGP_S2K_SALT + key_len;
158 : :
159 [ + + ]: 12573914 : while (curcnt < count)
160 : : {
161 [ + + ]: 12573891 : if (curcnt + PGP_S2K_SALT < count)
162 : 12573818 : c = PGP_S2K_SALT;
163 : : else
164 : 73 : c = count - curcnt;
165 : 12573891 : px_md_update(md, s2k->salt, c);
166 : 12573891 : curcnt += c;
167 : :
168 [ + + ]: 12573891 : if (curcnt + key_len < count)
169 : 12573795 : c = key_len;
170 [ + + ]: 96 : else if (curcnt < count)
171 : 23 : c = count - curcnt;
172 : : else
173 : 73 : break;
174 : 12573818 : px_md_update(md, key, c);
175 : 12573818 : curcnt += c;
176 : : }
177 : 96 : px_md_finish(md, buf);
178 : :
179 [ + + ]: 96 : if (remain > md_rlen)
180 : : {
181 : 13 : memcpy(dst, buf, md_rlen);
182 : 13 : remain -= md_rlen;
183 : 13 : dst += md_rlen;
184 : : }
185 : : else
186 : : {
187 : 83 : memcpy(dst, buf, remain);
188 : 83 : remain = 0;
189 : : }
190 : : }
3650 191 : 83 : px_memset(buf, 0, sizeof(buf));
6853 192 : 83 : return 0;
193 : : }
194 : :
195 : : /*
196 : : * Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation)
197 : : *
198 : : * Too small: weak
199 : : * Too big: slow
200 : : * gpg defaults to 96 => 65536 iters
201 : : *
202 : : * For our default (count=-1) we let it float a bit: 96 + 32 => between 65536
203 : : * and 262144 iterations.
204 : : *
205 : : * Otherwise, find the smallest number which provides at least the specified
206 : : * iteration count.
207 : : */
208 : : static uint8
2958 alvherre@alvh.no-ip. 209 : 28 : decide_s2k_iter(unsigned rand_byte, int count)
210 : : {
211 : : int iter;
212 : :
213 [ + + ]: 28 : if (count == -1)
214 : 26 : return 96 + (rand_byte & 0x1F);
215 : : /* this is a bit brute-force, but should be quick enough */
216 [ + - ]: 257 : for (iter = 0; iter <= 255; iter++)
217 [ + + ]: 257 : if (s2k_decode_count(iter) >= count)
218 : 2 : return iter;
2958 alvherre@alvh.no-ip. 219 :UBC 0 : return 255;
220 : : }
221 : :
222 : : int
2958 alvherre@alvh.no-ip. 223 :CBC 30 : pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
224 : : {
6756 bruce@momjian.us 225 : 30 : int res = 0;
226 : : uint8 tmp;
227 : :
6853 228 : 30 : s2k->mode = mode;
229 : 30 : s2k->digest_algo = digest_algo;
230 : :
6756 231 [ + + + - ]: 30 : switch (s2k->mode)
232 : : {
2958 alvherre@alvh.no-ip. 233 : 1 : case PGP_S2K_SIMPLE:
6853 bruce@momjian.us 234 : 1 : break;
2958 alvherre@alvh.no-ip. 235 : 1 : case PGP_S2K_SALTED:
1930 michael@paquier.xyz 236 [ - + ]: 1 : if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
2687 heikki.linnakangas@i 237 :UBC 0 : return PXE_NO_RANDOM;
6853 bruce@momjian.us 238 :CBC 1 : break;
2958 alvherre@alvh.no-ip. 239 : 28 : case PGP_S2K_ISALTED:
1930 michael@paquier.xyz 240 [ - + ]: 28 : if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
2687 heikki.linnakangas@i 241 :UBC 0 : return PXE_NO_RANDOM;
1930 michael@paquier.xyz 242 [ - + ]:CBC 28 : if (!pg_strong_random(&tmp, 1))
2687 heikki.linnakangas@i 243 :UBC 0 : return PXE_NO_RANDOM;
2958 alvherre@alvh.no-ip. 244 :CBC 28 : s2k->iter = decide_s2k_iter(tmp, count);
6853 bruce@momjian.us 245 : 28 : break;
6853 bruce@momjian.us 246 :UBC 0 : default:
247 : 0 : res = PXE_PGP_BAD_S2K_MODE;
248 : : }
6853 bruce@momjian.us 249 :CBC 30 : return res;
250 : : }
251 : :
252 : : int
5421 253 : 63 : pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
254 : : {
6756 255 : 63 : int res = 0;
256 : :
6853 257 [ - + ]: 63 : GETBYTE(src, s2k->mode);
258 [ - + ]: 63 : GETBYTE(src, s2k->digest_algo);
6756 259 [ + + + - ]: 63 : switch (s2k->mode)
260 : : {
6853 261 : 4 : case 0:
262 : 4 : break;
263 : 4 : case 1:
264 : 4 : res = pullf_read_fixed(src, 8, s2k->salt);
265 : 4 : break;
266 : 55 : case 3:
267 : 55 : res = pullf_read_fixed(src, 8, s2k->salt);
268 [ - + ]: 55 : if (res < 0)
6853 bruce@momjian.us 269 :UBC 0 : break;
6853 bruce@momjian.us 270 [ - + ]:CBC 55 : GETBYTE(src, s2k->iter);
271 : 55 : break;
6853 bruce@momjian.us 272 :UBC 0 : default:
273 : 0 : res = PXE_PGP_BAD_S2K_MODE;
274 : : }
6853 bruce@momjian.us 275 :CBC 63 : return res;
276 : : }
277 : :
278 : : int
5421 279 : 93 : pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
280 : : {
281 : : int res;
282 : : PX_MD *md;
283 : :
6853 284 : 93 : s2k->key_len = pgp_get_cipher_key_size(cipher);
285 [ - + ]: 93 : if (s2k->key_len <= 0)
6853 bruce@momjian.us 286 :UBC 0 : return PXE_PGP_UNSUPPORTED_CIPHER;
287 : :
6853 bruce@momjian.us 288 :CBC 93 : res = pgp_load_digest(s2k->digest_algo, &md);
289 [ - + ]: 93 : if (res < 0)
6853 bruce@momjian.us 290 :UBC 0 : return res;
291 : :
6756 bruce@momjian.us 292 [ + + + - ]:CBC 93 : switch (s2k->mode)
293 : : {
6853 294 : 5 : case 0:
295 : 5 : res = calc_s2k_simple(s2k, md, key, key_len);
296 : 5 : break;
297 : 5 : case 1:
298 : 5 : res = calc_s2k_salted(s2k, md, key, key_len);
299 : 5 : break;
300 : 83 : case 3:
301 : 83 : res = calc_s2k_iter_salted(s2k, md, key, key_len);
302 : 83 : break;
6853 bruce@momjian.us 303 :UBC 0 : default:
304 : 0 : res = PXE_PGP_BAD_S2K_MODE;
305 : : }
6853 bruce@momjian.us 306 :CBC 93 : px_md_free(md);
307 : 93 : return res;
308 : : }
|