OSDN Git Service

Merge branch 'REL9_0_STABLE' into pgrex90-base
[pg-rex/syncrep.git] / contrib / pgcrypto / pgcrypto.c
1 /*
2  * pgcrypto.c
3  *              Various cryptographic stuff for PostgreSQL.
4  *
5  * Copyright (c) 2001 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  * $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.27 2008/03/25 22:42:41 tgl Exp $
30  */
31
32 #include "postgres.h"
33
34 #include <ctype.h>
35
36 #include "fmgr.h"
37 #include "parser/scansup.h"
38 #include "utils/builtins.h"
39
40 #include "px.h"
41 #include "px-crypt.h"
42 #include "pgcrypto.h"
43
44 PG_MODULE_MAGIC;
45
46 /* private stuff */
47
48 typedef int (*PFN) (const char *name, void **res);
49 static void *find_provider(text *name, PFN pf, char *desc, int silent);
50
51 /* SQL function: hash(bytea, text) returns bytea */
52 PG_FUNCTION_INFO_V1(pg_digest);
53
54 Datum
55 pg_digest(PG_FUNCTION_ARGS)
56 {
57         bytea      *arg;
58         text       *name;
59         unsigned        len,
60                                 hlen;
61         PX_MD      *md;
62         bytea      *res;
63
64         name = PG_GETARG_TEXT_P(1);
65
66         /* will give error if fails */
67         md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
68
69         hlen = px_md_result_size(md);
70
71         res = (text *) palloc(hlen + VARHDRSZ);
72         SET_VARSIZE(res, hlen + VARHDRSZ);
73
74         arg = PG_GETARG_BYTEA_P(0);
75         len = VARSIZE(arg) - VARHDRSZ;
76
77         px_md_update(md, (uint8 *) VARDATA(arg), len);
78         px_md_finish(md, (uint8 *) VARDATA(res));
79         px_md_free(md);
80
81         PG_FREE_IF_COPY(arg, 0);
82         PG_FREE_IF_COPY(name, 1);
83
84         PG_RETURN_BYTEA_P(res);
85 }
86
87 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
88 PG_FUNCTION_INFO_V1(pg_hmac);
89
90 Datum
91 pg_hmac(PG_FUNCTION_ARGS)
92 {
93         bytea      *arg;
94         bytea      *key;
95         text       *name;
96         unsigned        len,
97                                 hlen,
98                                 klen;
99         PX_HMAC    *h;
100         bytea      *res;
101
102         name = PG_GETARG_TEXT_P(2);
103
104         /* will give error if fails */
105         h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
106
107         hlen = px_hmac_result_size(h);
108
109         res = (text *) palloc(hlen + VARHDRSZ);
110         SET_VARSIZE(res, hlen + VARHDRSZ);
111
112         arg = PG_GETARG_BYTEA_P(0);
113         key = PG_GETARG_BYTEA_P(1);
114         len = VARSIZE(arg) - VARHDRSZ;
115         klen = VARSIZE(key) - VARHDRSZ;
116
117         px_hmac_init(h, (uint8 *) VARDATA(key), klen);
118         px_hmac_update(h, (uint8 *) VARDATA(arg), len);
119         px_hmac_finish(h, (uint8 *) VARDATA(res));
120         px_hmac_free(h);
121
122         PG_FREE_IF_COPY(arg, 0);
123         PG_FREE_IF_COPY(key, 1);
124         PG_FREE_IF_COPY(name, 2);
125
126         PG_RETURN_BYTEA_P(res);
127 }
128
129
130 /* SQL function: pg_gen_salt(text) returns text */
131 PG_FUNCTION_INFO_V1(pg_gen_salt);
132
133 Datum
134 pg_gen_salt(PG_FUNCTION_ARGS)
135 {
136         text       *arg0 = PG_GETARG_TEXT_PP(0);
137         int                     len;
138         char            buf[PX_MAX_SALT_LEN + 1];
139
140         text_to_cstring_buffer(arg0, buf, sizeof(buf));
141         len = px_gen_salt(buf, buf, 0);
142         if (len < 0)
143                 ereport(ERROR,
144                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
145                                  errmsg("gen_salt: %s", px_strerror(len))));
146
147         PG_FREE_IF_COPY(arg0, 0);
148
149         PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
150 }
151
152 /* SQL function: pg_gen_salt(text, int4) returns text */
153 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
154
155 Datum
156 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
157 {
158         text       *arg0 = PG_GETARG_TEXT_PP(0);
159         int                     rounds = PG_GETARG_INT32(1);
160         int                     len;
161         char            buf[PX_MAX_SALT_LEN + 1];
162
163         text_to_cstring_buffer(arg0, buf, sizeof(buf));
164         len = px_gen_salt(buf, buf, rounds);
165         if (len < 0)
166                 ereport(ERROR,
167                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
168                                  errmsg("gen_salt: %s", px_strerror(len))));
169
170         PG_FREE_IF_COPY(arg0, 0);
171
172         PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
173 }
174
175 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
176 PG_FUNCTION_INFO_V1(pg_crypt);
177
178 Datum
179 pg_crypt(PG_FUNCTION_ARGS)
180 {
181         text       *arg0 = PG_GETARG_TEXT_PP(0);
182         text       *arg1 = PG_GETARG_TEXT_PP(1);
183         char       *buf0,
184                            *buf1,
185                            *cres,
186                            *resbuf;
187         text       *res;
188
189         buf0 = text_to_cstring(arg0);
190         buf1 = text_to_cstring(arg1);
191
192         resbuf = palloc0(PX_MAX_CRYPT);
193
194         cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
195
196         pfree(buf0);
197         pfree(buf1);
198
199         if (cres == NULL)
200                 ereport(ERROR,
201                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
202                                  errmsg("crypt(3) returned NULL")));
203
204         res = cstring_to_text(cres);
205
206         pfree(resbuf);
207
208         PG_FREE_IF_COPY(arg0, 0);
209         PG_FREE_IF_COPY(arg1, 1);
210
211         PG_RETURN_TEXT_P(res);
212 }
213
214 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
215 PG_FUNCTION_INFO_V1(pg_encrypt);
216
217 Datum
218 pg_encrypt(PG_FUNCTION_ARGS)
219 {
220         int                     err;
221         bytea      *data,
222                            *key,
223                            *res;
224         text       *type;
225         PX_Combo   *c;
226         unsigned        dlen,
227                                 klen,
228                                 rlen;
229
230         type = PG_GETARG_TEXT_P(2);
231         c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
232
233         data = PG_GETARG_BYTEA_P(0);
234         key = PG_GETARG_BYTEA_P(1);
235         dlen = VARSIZE(data) - VARHDRSZ;
236         klen = VARSIZE(key) - VARHDRSZ;
237
238         rlen = px_combo_encrypt_len(c, dlen);
239         res = palloc(VARHDRSZ + rlen);
240
241         err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
242         if (!err)
243                 err = px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
244                                                            (uint8 *) VARDATA(res), &rlen);
245         px_combo_free(c);
246
247         PG_FREE_IF_COPY(data, 0);
248         PG_FREE_IF_COPY(key, 1);
249         PG_FREE_IF_COPY(type, 2);
250
251         if (err)
252         {
253                 pfree(res);
254                 ereport(ERROR,
255                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
256                                  errmsg("encrypt error: %s", px_strerror(err))));
257         }
258
259         SET_VARSIZE(res, VARHDRSZ + rlen);
260         PG_RETURN_BYTEA_P(res);
261 }
262
263 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
264 PG_FUNCTION_INFO_V1(pg_decrypt);
265
266 Datum
267 pg_decrypt(PG_FUNCTION_ARGS)
268 {
269         int                     err;
270         bytea      *data,
271                            *key,
272                            *res;
273         text       *type;
274         PX_Combo   *c;
275         unsigned        dlen,
276                                 klen,
277                                 rlen;
278
279         type = PG_GETARG_TEXT_P(2);
280         c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
281
282         data = PG_GETARG_BYTEA_P(0);
283         key = PG_GETARG_BYTEA_P(1);
284         dlen = VARSIZE(data) - VARHDRSZ;
285         klen = VARSIZE(key) - VARHDRSZ;
286
287         rlen = px_combo_decrypt_len(c, dlen);
288         res = palloc(VARHDRSZ + rlen);
289
290         err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
291         if (!err)
292                 err = px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
293                                                            (uint8 *) VARDATA(res), &rlen);
294
295         px_combo_free(c);
296
297         if (err)
298                 ereport(ERROR,
299                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
300                                  errmsg("decrypt error: %s", px_strerror(err))));
301
302         SET_VARSIZE(res, VARHDRSZ + rlen);
303
304         PG_FREE_IF_COPY(data, 0);
305         PG_FREE_IF_COPY(key, 1);
306         PG_FREE_IF_COPY(type, 2);
307
308         PG_RETURN_BYTEA_P(res);
309 }
310
311 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
312 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
313
314 Datum
315 pg_encrypt_iv(PG_FUNCTION_ARGS)
316 {
317         int                     err;
318         bytea      *data,
319                            *key,
320                            *iv,
321                            *res;
322         text       *type;
323         PX_Combo   *c;
324         unsigned        dlen,
325                                 klen,
326                                 ivlen,
327                                 rlen;
328
329         type = PG_GETARG_TEXT_P(3);
330         c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
331
332         data = PG_GETARG_BYTEA_P(0);
333         key = PG_GETARG_BYTEA_P(1);
334         iv = PG_GETARG_BYTEA_P(2);
335         dlen = VARSIZE(data) - VARHDRSZ;
336         klen = VARSIZE(key) - VARHDRSZ;
337         ivlen = VARSIZE(iv) - VARHDRSZ;
338
339         rlen = px_combo_encrypt_len(c, dlen);
340         res = palloc(VARHDRSZ + rlen);
341
342         err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
343                                                 (uint8 *) VARDATA(iv), ivlen);
344         if (!err)
345                 px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
346                                                  (uint8 *) VARDATA(res), &rlen);
347
348         px_combo_free(c);
349
350         if (err)
351                 ereport(ERROR,
352                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
353                                  errmsg("encrypt_iv error: %s", px_strerror(err))));
354
355         SET_VARSIZE(res, VARHDRSZ + rlen);
356
357         PG_FREE_IF_COPY(data, 0);
358         PG_FREE_IF_COPY(key, 1);
359         PG_FREE_IF_COPY(iv, 2);
360         PG_FREE_IF_COPY(type, 3);
361
362         PG_RETURN_BYTEA_P(res);
363 }
364
365 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
366 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
367
368 Datum
369 pg_decrypt_iv(PG_FUNCTION_ARGS)
370 {
371         int                     err;
372         bytea      *data,
373                            *key,
374                            *iv,
375                            *res;
376         text       *type;
377         PX_Combo   *c;
378         unsigned        dlen,
379                                 klen,
380                                 rlen,
381                                 ivlen;
382
383         type = PG_GETARG_TEXT_P(3);
384         c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
385
386         data = PG_GETARG_BYTEA_P(0);
387         key = PG_GETARG_BYTEA_P(1);
388         iv = PG_GETARG_BYTEA_P(2);
389         dlen = VARSIZE(data) - VARHDRSZ;
390         klen = VARSIZE(key) - VARHDRSZ;
391         ivlen = VARSIZE(iv) - VARHDRSZ;
392
393         rlen = px_combo_decrypt_len(c, dlen);
394         res = palloc(VARHDRSZ + rlen);
395
396         err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
397                                                 (uint8 *) VARDATA(iv), ivlen);
398         if (!err)
399                 px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
400                                                  (uint8 *) VARDATA(res), &rlen);
401
402         px_combo_free(c);
403
404         if (err)
405                 ereport(ERROR,
406                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
407                                  errmsg("decrypt_iv error: %s", px_strerror(err))));
408
409         SET_VARSIZE(res, VARHDRSZ + rlen);
410
411         PG_FREE_IF_COPY(data, 0);
412         PG_FREE_IF_COPY(key, 1);
413         PG_FREE_IF_COPY(iv, 2);
414         PG_FREE_IF_COPY(type, 3);
415
416         PG_RETURN_BYTEA_P(res);
417 }
418
419 /* SQL function: pg_random_bytes(int4) returns bytea */
420 PG_FUNCTION_INFO_V1(pg_random_bytes);
421
422 Datum
423 pg_random_bytes(PG_FUNCTION_ARGS)
424 {
425         int                     err;
426         int                     len = PG_GETARG_INT32(0);
427         bytea      *res;
428
429         if (len < 1 || len > 1024)
430                 ereport(ERROR,
431                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
432                                  errmsg("Length not in range")));
433
434         res = palloc(VARHDRSZ + len);
435         SET_VARSIZE(res, VARHDRSZ + len);
436
437         /* generate result */
438         err = px_get_random_bytes((uint8 *) VARDATA(res), len);
439         if (err < 0)
440                 ereport(ERROR,
441                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
442                                  errmsg("Random generator error: %s", px_strerror(err))));
443
444         PG_RETURN_BYTEA_P(res);
445 }
446
447 static void *
448 find_provider(text *name,
449                           PFN provider_lookup,
450                           char *desc, int silent)
451 {
452         void       *res;
453         char       *buf;
454         int                     err;
455
456         buf = downcase_truncate_identifier(VARDATA(name),
457                                                                            VARSIZE(name) - VARHDRSZ,
458                                                                            false);
459
460         err = provider_lookup(buf, &res);
461
462         if (err && !silent)
463                 ereport(ERROR,
464                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
465                                  errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
466
467         pfree(buf);
468
469         return err ? NULL : res;
470 }