]> granicus.if.org Git - postgresql/blob - contrib/pgcrypto/pgp-pgsql.c
8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[postgresql] / contrib / pgcrypto / pgp-pgsql.c
1 /*
2  * pgp-pgsql.c
3  *              PostgreSQL wrappers for pgp.
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  * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pgsql.c,v 1.11 2009/06/11 14:48:52 momjian Exp $
30  */
31
32 #include "postgres.h"
33
34 #include "fmgr.h"
35 #include "parser/scansup.h"
36 #include "mb/pg_wchar.h"
37 #include "utils/builtins.h"
38
39 #include "mbuf.h"
40 #include "px.h"
41 #include "pgp.h"
42
43 /*
44  * public functions
45  */
46 Datum           pgp_sym_encrypt_text(PG_FUNCTION_ARGS);
47 Datum           pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS);
48 Datum           pgp_sym_decrypt_text(PG_FUNCTION_ARGS);
49 Datum           pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS);
50
51 Datum           pgp_pub_encrypt_text(PG_FUNCTION_ARGS);
52 Datum           pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS);
53 Datum           pgp_pub_decrypt_text(PG_FUNCTION_ARGS);
54 Datum           pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS);
55
56 Datum           pgp_key_id_w(PG_FUNCTION_ARGS);
57
58 Datum           pg_armor(PG_FUNCTION_ARGS);
59 Datum           pg_dearmor(PG_FUNCTION_ARGS);
60
61 /* function headers */
62
63 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
64 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
65 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
66 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
67
68 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
69 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
70 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
71 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
72
73 PG_FUNCTION_INFO_V1(pgp_key_id_w);
74
75 PG_FUNCTION_INFO_V1(pg_armor);
76 PG_FUNCTION_INFO_V1(pg_dearmor);
77
78 /*
79  * Mix a block of data into RNG.
80  */
81 static void
82 add_block_entropy(PX_MD *md, text *data)
83 {
84         uint8           sha1[20];
85
86         px_md_reset(md);
87         px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ);
88         px_md_finish(md, sha1);
89
90         px_add_entropy(sha1, 20);
91
92         memset(sha1, 0, 20);
93 }
94
95 /*
96  * Mix user data into RNG.      It is for user own interests to have
97  * RNG state shuffled.
98  */
99 static void
100 add_entropy(text *data1, text *data2, text *data3)
101 {
102         PX_MD      *md;
103         uint8           rnd[3];
104
105         if (!data1 && !data2 && !data3)
106                 return;
107
108         if (px_get_random_bytes(rnd, 3) < 0)
109                 return;
110
111         if (px_find_digest("sha1", &md) < 0)
112                 return;
113
114         /*
115          * Try to make the feeding unpredictable.
116          *
117          * Prefer data over keys, as it's rather likely that key is same in
118          * several calls.
119          */
120
121         /* chance: 7/8 */
122         if (data1 && rnd[0] >= 32)
123                 add_block_entropy(md, data1);
124
125         /* chance: 5/8 */
126         if (data2 && rnd[1] >= 160)
127                 add_block_entropy(md, data2);
128
129         /* chance: 5/8 */
130         if (data3 && rnd[2] >= 160)
131                 add_block_entropy(md, data3);
132
133         px_md_free(md);
134         memset(rnd, 0, sizeof(rnd));
135 }
136
137 /*
138  * returns src in case of no conversion or error
139  */
140 static text *
141 convert_charset(text *src, int cset_from, int cset_to)
142 {
143         int                     src_len = VARSIZE(src) - VARHDRSZ;
144         unsigned char *dst;
145         unsigned char *csrc = (unsigned char *) VARDATA(src);
146         text       *res;
147
148         dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
149         if (dst == csrc)
150                 return src;
151
152         res = cstring_to_text((char *) dst);
153         pfree(dst);
154         return res;
155 }
156
157 static text *
158 convert_from_utf8(text *src)
159 {
160         return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
161 }
162
163 static text *
164 convert_to_utf8(text *src)
165 {
166         return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
167 }
168
169 static void
170 clear_and_pfree(text *p)
171 {
172         memset(p, 0, VARSIZE(p));
173         pfree(p);
174 }
175
176 /*
177  * expect-* arguments storage
178  */
179 struct debug_expect
180 {
181         int                     debug;
182         int                     expect;
183         int                     cipher_algo;
184         int                     s2k_mode;
185         int                     s2k_cipher_algo;
186         int                     s2k_digest_algo;
187         int                     compress_algo;
188         int                     use_sess_key;
189         int                     disable_mdc;
190         int                     unicode_mode;
191 };
192
193 static void
194 fill_expect(struct debug_expect * ex, int text_mode)
195 {
196         ex->debug = 0;
197         ex->expect = 0;
198         ex->cipher_algo = -1;
199         ex->s2k_mode = -1;
200         ex->s2k_cipher_algo = -1;
201         ex->s2k_digest_algo = -1;
202         ex->compress_algo = -1;
203         ex->use_sess_key = -1;
204         ex->disable_mdc = -1;
205         ex->unicode_mode = -1;
206 }
207
208 #define EX_MSG(arg) \
209         ereport(NOTICE, (errmsg( \
210                 "pgp_decrypt: unexpected %s: expected %d got %d", \
211                 CppAsString(arg), ex->arg, ctx->arg)))
212
213 #define EX_CHECK(arg) do { \
214                 if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
215         } while (0)
216
217 static void
218 check_expect(PGP_Context *ctx, struct debug_expect * ex)
219 {
220         EX_CHECK(cipher_algo);
221         EX_CHECK(s2k_mode);
222         EX_CHECK(s2k_digest_algo);
223         EX_CHECK(use_sess_key);
224         if (ctx->use_sess_key)
225                 EX_CHECK(s2k_cipher_algo);
226         EX_CHECK(disable_mdc);
227         EX_CHECK(compress_algo);
228         EX_CHECK(unicode_mode);
229 }
230
231 static void
232 show_debug(const char *msg)
233 {
234         ereport(NOTICE, (errmsg("dbg: %s", msg)));
235 }
236
237 static int
238 set_arg(PGP_Context *ctx, char *key, char *val,
239                 struct debug_expect * ex)
240 {
241         int                     res = 0;
242
243         if (strcmp(key, "cipher-algo") == 0)
244                 res = pgp_set_cipher_algo(ctx, val);
245         else if (strcmp(key, "disable-mdc") == 0)
246                 res = pgp_disable_mdc(ctx, atoi(val));
247         else if (strcmp(key, "sess-key") == 0)
248                 res = pgp_set_sess_key(ctx, atoi(val));
249         else if (strcmp(key, "s2k-mode") == 0)
250                 res = pgp_set_s2k_mode(ctx, atoi(val));
251         else if (strcmp(key, "s2k-digest-algo") == 0)
252                 res = pgp_set_s2k_digest_algo(ctx, val);
253         else if (strcmp(key, "s2k-cipher-algo") == 0)
254                 res = pgp_set_s2k_cipher_algo(ctx, val);
255         else if (strcmp(key, "compress-algo") == 0)
256                 res = pgp_set_compress_algo(ctx, atoi(val));
257         else if (strcmp(key, "compress-level") == 0)
258                 res = pgp_set_compress_level(ctx, atoi(val));
259         else if (strcmp(key, "convert-crlf") == 0)
260                 res = pgp_set_convert_crlf(ctx, atoi(val));
261         else if (strcmp(key, "unicode-mode") == 0)
262                 res = pgp_set_unicode_mode(ctx, atoi(val));
263         /* decrypt debug */
264         else if (ex != NULL && strcmp(key, "debug") == 0)
265                 ex->debug = atoi(val);
266         else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0)
267         {
268                 ex->expect = 1;
269                 ex->cipher_algo = pgp_get_cipher_code(val);
270         }
271         else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
272         {
273                 ex->expect = 1;
274                 ex->disable_mdc = atoi(val);
275         }
276         else if (ex != NULL && strcmp(key, "expect-sess-key") == 0)
277         {
278                 ex->expect = 1;
279                 ex->use_sess_key = atoi(val);
280         }
281         else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0)
282         {
283                 ex->expect = 1;
284                 ex->s2k_mode = atoi(val);
285         }
286         else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
287         {
288                 ex->expect = 1;
289                 ex->s2k_digest_algo = pgp_get_digest_code(val);
290         }
291         else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0)
292         {
293                 ex->expect = 1;
294                 ex->s2k_cipher_algo = pgp_get_cipher_code(val);
295         }
296         else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0)
297         {
298                 ex->expect = 1;
299                 ex->compress_algo = atoi(val);
300         }
301         else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0)
302         {
303                 ex->expect = 1;
304                 ex->unicode_mode = atoi(val);
305         }
306         else
307                 res = PXE_ARGUMENT_ERROR;
308
309         return res;
310 }
311
312 /*
313  * Find next word.      Handle ',' and '=' as words.  Skip whitespace.
314  * Put word info into res_p, res_len.
315  * Returns ptr to next word.
316  */
317 static char *
318 getword(char *p, char **res_p, int *res_len)
319 {
320         /* whitespace at start */
321         while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
322                 p++;
323
324         /* word data */
325         *res_p = p;
326         if (*p == '=' || *p == ',')
327                 p++;
328         else
329                 while (*p && !(*p == ' ' || *p == '\t' || *p == '\n'
330                                            || *p == '=' || *p == ','))
331                         p++;
332
333         /* word end */
334         *res_len = p - *res_p;
335
336         /* whitespace at end */
337         while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
338                 p++;
339
340         return p;
341 }
342
343 /*
344  * Convert to lowercase asciiz string.
345  */
346 static char *
347 downcase_convert(const uint8 *s, int len)
348 {
349         int                     c,
350                                 i;
351         char       *res = palloc(len + 1);
352
353         for (i = 0; i < len; i++)
354         {
355                 c = s[i];
356                 if (c >= 'A' && c <= 'Z')
357                         c += 'a' - 'A';
358                 res[i] = c;
359         }
360         res[len] = 0;
361         return res;
362 }
363
364 static int
365 parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
366                    struct debug_expect * ex)
367 {
368         char       *str = downcase_convert(args, arg_len);
369         char       *key,
370                            *val;
371         int                     key_len,
372                                 val_len;
373         int                     res = 0;
374         char       *p = str;
375
376         while (*p)
377         {
378                 res = PXE_ARGUMENT_ERROR;
379                 p = getword(p, &key, &key_len);
380                 if (*p++ != '=')
381                         break;
382                 p = getword(p, &val, &val_len);
383                 if (*p == '\0')
384                         ;
385                 else if (*p++ != ',')
386                         break;
387
388                 if (*key == 0 || *val == 0 || val_len == 0)
389                         break;
390
391                 key[key_len] = 0;
392                 val[val_len] = 0;
393
394                 res = set_arg(ctx, key, val, ex);
395                 if (res < 0)
396                         break;
397         }
398         pfree(str);
399         return res;
400 }
401
402 static MBuf *
403 create_mbuf_from_vardata(text *data)
404 {
405         return mbuf_create_from_data((uint8 *) VARDATA(data),
406                                                                  VARSIZE(data) - VARHDRSZ);
407 }
408
409 static void
410 init_work(PGP_Context **ctx_p, int is_text,
411                   text *args, struct debug_expect * ex)
412 {
413         int                     err = pgp_init(ctx_p);
414
415         fill_expect(ex, is_text);
416
417         if (err == 0 && args != NULL)
418                 err = parse_args(*ctx_p, (uint8 *) VARDATA(args),
419                                                  VARSIZE(args) - VARHDRSZ, ex);
420
421         if (err)
422         {
423                 ereport(ERROR,
424                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
425                                  errmsg("%s", px_strerror(err))));
426         }
427
428         if (ex->debug)
429                 px_set_debug_handler(show_debug);
430
431         pgp_set_text_mode(*ctx_p, is_text);
432 }
433
434 static bytea *
435 encrypt_internal(int is_pubenc, int is_text,
436                                  text *data, text *key, text *args)
437 {
438         MBuf       *src,
439                            *dst;
440         uint8           tmp[VARHDRSZ];
441         uint8      *restmp;
442         bytea      *res;
443         int                     res_len;
444         PGP_Context *ctx;
445         int                     err;
446         struct debug_expect ex;
447         text       *tmp_data = NULL;
448
449         /*
450          * Add data and key info RNG.
451          */
452         add_entropy(data, key, NULL);
453
454         init_work(&ctx, is_text, args, &ex);
455
456         if (is_text && pgp_get_unicode_mode(ctx))
457         {
458                 tmp_data = convert_to_utf8(data);
459                 if (tmp_data == data)
460                         tmp_data = NULL;
461                 else
462                         data = tmp_data;
463         }
464
465         src = create_mbuf_from_vardata(data);
466         dst = mbuf_create(VARSIZE(data) + 128);
467
468         /*
469          * reserve room for header
470          */
471         mbuf_append(dst, tmp, VARHDRSZ);
472
473         /*
474          * set key
475          */
476         if (is_pubenc)
477         {
478                 MBuf       *kbuf = create_mbuf_from_vardata(key);
479
480                 err = pgp_set_pubkey(ctx, kbuf,
481                                                          NULL, 0, 0);
482                 mbuf_free(kbuf);
483         }
484         else
485                 err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
486                                                          VARSIZE(key) - VARHDRSZ);
487
488         /*
489          * encrypt
490          */
491         if (err >= 0)
492                 err = pgp_encrypt(ctx, src, dst);
493
494         /*
495          * check for error
496          */
497         if (err)
498         {
499                 if (ex.debug)
500                         px_set_debug_handler(NULL);
501                 if (tmp_data)
502                         clear_and_pfree(tmp_data);
503                 pgp_free(ctx);
504                 mbuf_free(src);
505                 mbuf_free(dst);
506                 ereport(ERROR,
507                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
508                                  errmsg("%s", px_strerror(err))));
509         }
510
511         /* res_len includes VARHDRSZ */
512         res_len = mbuf_steal_data(dst, &restmp);
513         res = (bytea *) restmp;
514         SET_VARSIZE(res, res_len);
515
516         if (tmp_data)
517                 clear_and_pfree(tmp_data);
518         pgp_free(ctx);
519         mbuf_free(src);
520         mbuf_free(dst);
521
522         px_set_debug_handler(NULL);
523
524         return res;
525 }
526
527 static bytea *
528 decrypt_internal(int is_pubenc, int need_text, text *data,
529                                  text *key, text *keypsw, text *args)
530 {
531         int                     err;
532         MBuf       *src = NULL,
533                            *dst = NULL;
534         uint8           tmp[VARHDRSZ];
535         uint8      *restmp;
536         bytea      *res;
537         int                     res_len;
538         PGP_Context *ctx = NULL;
539         struct debug_expect ex;
540         int                     got_unicode = 0;
541
542
543         init_work(&ctx, need_text, args, &ex);
544
545         src = mbuf_create_from_data((uint8 *) VARDATA(data),
546                                                                 VARSIZE(data) - VARHDRSZ);
547         dst = mbuf_create(VARSIZE(data) + 2048);
548
549         /*
550          * reserve room for header
551          */
552         mbuf_append(dst, tmp, VARHDRSZ);
553
554         /*
555          * set key
556          */
557         if (is_pubenc)
558         {
559                 uint8      *psw = NULL;
560                 int                     psw_len = 0;
561                 MBuf       *kbuf;
562
563                 if (keypsw)
564                 {
565                         psw = (uint8 *) VARDATA(keypsw);
566                         psw_len = VARSIZE(keypsw) - VARHDRSZ;
567                 }
568                 kbuf = create_mbuf_from_vardata(key);
569                 err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
570                 mbuf_free(kbuf);
571         }
572         else
573                 err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
574                                                          VARSIZE(key) - VARHDRSZ);
575
576         /*
577          * decrypt
578          */
579         if (err >= 0)
580                 err = pgp_decrypt(ctx, src, dst);
581
582         /*
583          * failed?
584          */
585         if (err < 0)
586                 goto out;
587
588         if (ex.expect)
589                 check_expect(ctx, &ex);
590
591         /* remember the setting */
592         got_unicode = pgp_get_unicode_mode(ctx);
593
594 out:
595         if (src)
596                 mbuf_free(src);
597         if (ctx)
598                 pgp_free(ctx);
599
600         if (err)
601         {
602                 px_set_debug_handler(NULL);
603                 if (dst)
604                         mbuf_free(dst);
605                 ereport(ERROR,
606                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
607                                  errmsg("%s", px_strerror(err))));
608         }
609
610         res_len = mbuf_steal_data(dst, &restmp);
611         mbuf_free(dst);
612
613         /* res_len includes VARHDRSZ */
614         res = (bytea *) restmp;
615         SET_VARSIZE(res, res_len);
616
617         if (need_text && got_unicode)
618         {
619                 text       *utf = convert_from_utf8(res);
620
621                 if (utf != res)
622                 {
623                         clear_and_pfree(res);
624                         res = utf;
625                 }
626         }
627         px_set_debug_handler(NULL);
628
629         /*
630          * add successfull decryptions also into RNG
631          */
632         add_entropy(res, key, keypsw);
633
634         return res;
635 }
636
637 /*
638  * Wrappers for symmetric-key functions
639  */
640 Datum
641 pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
642 {
643         bytea      *data,
644                            *key;
645         text       *arg = NULL;
646         text       *res;
647
648         data = PG_GETARG_BYTEA_P(0);
649         key = PG_GETARG_BYTEA_P(1);
650         if (PG_NARGS() > 2)
651                 arg = PG_GETARG_BYTEA_P(2);
652
653         res = encrypt_internal(0, 0, data, key, arg);
654
655         PG_FREE_IF_COPY(data, 0);
656         PG_FREE_IF_COPY(key, 1);
657         if (PG_NARGS() > 2)
658                 PG_FREE_IF_COPY(arg, 2);
659         PG_RETURN_TEXT_P(res);
660 }
661
662 Datum
663 pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
664 {
665         bytea      *data,
666                            *key;
667         text       *arg = NULL;
668         text       *res;
669
670         data = PG_GETARG_BYTEA_P(0);
671         key = PG_GETARG_BYTEA_P(1);
672         if (PG_NARGS() > 2)
673                 arg = PG_GETARG_BYTEA_P(2);
674
675         res = encrypt_internal(0, 1, data, key, arg);
676
677         PG_FREE_IF_COPY(data, 0);
678         PG_FREE_IF_COPY(key, 1);
679         if (PG_NARGS() > 2)
680                 PG_FREE_IF_COPY(arg, 2);
681         PG_RETURN_TEXT_P(res);
682 }
683
684
685 Datum
686 pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
687 {
688         bytea      *data,
689                            *key;
690         text       *arg = NULL;
691         text       *res;
692
693         data = PG_GETARG_BYTEA_P(0);
694         key = PG_GETARG_BYTEA_P(1);
695         if (PG_NARGS() > 2)
696                 arg = PG_GETARG_BYTEA_P(2);
697
698         res = decrypt_internal(0, 0, data, key, NULL, arg);
699
700         PG_FREE_IF_COPY(data, 0);
701         PG_FREE_IF_COPY(key, 1);
702         if (PG_NARGS() > 2)
703                 PG_FREE_IF_COPY(arg, 2);
704         PG_RETURN_TEXT_P(res);
705 }
706
707 Datum
708 pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
709 {
710         bytea      *data,
711                            *key;
712         text       *arg = NULL;
713         text       *res;
714
715         data = PG_GETARG_BYTEA_P(0);
716         key = PG_GETARG_BYTEA_P(1);
717         if (PG_NARGS() > 2)
718                 arg = PG_GETARG_BYTEA_P(2);
719
720         res = decrypt_internal(0, 1, data, key, NULL, arg);
721
722         PG_FREE_IF_COPY(data, 0);
723         PG_FREE_IF_COPY(key, 1);
724         if (PG_NARGS() > 2)
725                 PG_FREE_IF_COPY(arg, 2);
726         PG_RETURN_TEXT_P(res);
727 }
728
729 /*
730  * Wrappers for public-key functions
731  */
732
733 Datum
734 pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
735 {
736         bytea      *data,
737                            *key;
738         text       *arg = NULL;
739         text       *res;
740
741         data = PG_GETARG_BYTEA_P(0);
742         key = PG_GETARG_BYTEA_P(1);
743         if (PG_NARGS() > 2)
744                 arg = PG_GETARG_BYTEA_P(2);
745
746         res = encrypt_internal(1, 0, data, key, arg);
747
748         PG_FREE_IF_COPY(data, 0);
749         PG_FREE_IF_COPY(key, 1);
750         if (PG_NARGS() > 2)
751                 PG_FREE_IF_COPY(arg, 2);
752         PG_RETURN_TEXT_P(res);
753 }
754
755 Datum
756 pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
757 {
758         bytea      *data,
759                            *key;
760         text       *arg = NULL;
761         text       *res;
762
763         data = PG_GETARG_BYTEA_P(0);
764         key = PG_GETARG_BYTEA_P(1);
765         if (PG_NARGS() > 2)
766                 arg = PG_GETARG_BYTEA_P(2);
767
768         res = encrypt_internal(1, 1, data, key, arg);
769
770         PG_FREE_IF_COPY(data, 0);
771         PG_FREE_IF_COPY(key, 1);
772         if (PG_NARGS() > 2)
773                 PG_FREE_IF_COPY(arg, 2);
774         PG_RETURN_TEXT_P(res);
775 }
776
777
778 Datum
779 pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
780 {
781         bytea      *data,
782                            *key;
783         text       *psw = NULL,
784                            *arg = NULL;
785         text       *res;
786
787         data = PG_GETARG_BYTEA_P(0);
788         key = PG_GETARG_BYTEA_P(1);
789         if (PG_NARGS() > 2)
790                 psw = PG_GETARG_BYTEA_P(2);
791         if (PG_NARGS() > 3)
792                 arg = PG_GETARG_BYTEA_P(3);
793
794         res = decrypt_internal(1, 0, data, key, psw, arg);
795
796         PG_FREE_IF_COPY(data, 0);
797         PG_FREE_IF_COPY(key, 1);
798         if (PG_NARGS() > 2)
799                 PG_FREE_IF_COPY(psw, 2);
800         if (PG_NARGS() > 3)
801                 PG_FREE_IF_COPY(arg, 3);
802         PG_RETURN_TEXT_P(res);
803 }
804
805 Datum
806 pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
807 {
808         bytea      *data,
809                            *key;
810         text       *psw = NULL,
811                            *arg = NULL;
812         text       *res;
813
814         data = PG_GETARG_BYTEA_P(0);
815         key = PG_GETARG_BYTEA_P(1);
816         if (PG_NARGS() > 2)
817                 psw = PG_GETARG_BYTEA_P(2);
818         if (PG_NARGS() > 3)
819                 arg = PG_GETARG_BYTEA_P(3);
820
821         res = decrypt_internal(1, 1, data, key, psw, arg);
822
823         PG_FREE_IF_COPY(data, 0);
824         PG_FREE_IF_COPY(key, 1);
825         if (PG_NARGS() > 2)
826                 PG_FREE_IF_COPY(psw, 2);
827         if (PG_NARGS() > 3)
828                 PG_FREE_IF_COPY(arg, 3);
829         PG_RETURN_TEXT_P(res);
830 }
831
832
833 /*
834  * Wrappers for PGP ascii armor
835  */
836
837 Datum
838 pg_armor(PG_FUNCTION_ARGS)
839 {
840         bytea      *data;
841         text       *res;
842         int                     data_len,
843                                 res_len,
844                                 guess_len;
845
846         data = PG_GETARG_BYTEA_P(0);
847         data_len = VARSIZE(data) - VARHDRSZ;
848
849         guess_len = pgp_armor_enc_len(data_len);
850         res = palloc(VARHDRSZ + guess_len);
851
852         res_len = pgp_armor_encode((uint8 *) VARDATA(data), data_len,
853                                                            (uint8 *) VARDATA(res));
854         if (res_len > guess_len)
855                 ereport(ERROR,
856                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
857                                  errmsg("Overflow - encode estimate too small")));
858         SET_VARSIZE(res, VARHDRSZ + res_len);
859
860         PG_FREE_IF_COPY(data, 0);
861         PG_RETURN_TEXT_P(res);
862 }
863
864 Datum
865 pg_dearmor(PG_FUNCTION_ARGS)
866 {
867         text       *data;
868         bytea      *res;
869         int                     data_len,
870                                 res_len,
871                                 guess_len;
872
873         data = PG_GETARG_TEXT_P(0);
874         data_len = VARSIZE(data) - VARHDRSZ;
875
876         guess_len = pgp_armor_dec_len(data_len);
877         res = palloc(VARHDRSZ + guess_len);
878
879         res_len = pgp_armor_decode((uint8 *) VARDATA(data), data_len,
880                                                            (uint8 *) VARDATA(res));
881         if (res_len < 0)
882                 ereport(ERROR,
883                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
884                                  errmsg("%s", px_strerror(res_len))));
885         if (res_len > guess_len)
886                 ereport(ERROR,
887                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
888                                  errmsg("Overflow - decode estimate too small")));
889         SET_VARSIZE(res, VARHDRSZ + res_len);
890
891         PG_FREE_IF_COPY(data, 0);
892         PG_RETURN_TEXT_P(res);
893 }
894
895 /*
896  * Wrappers for PGP key id
897  */
898
899 Datum
900 pgp_key_id_w(PG_FUNCTION_ARGS)
901 {
902         bytea      *data;
903         text       *res;
904         int                     res_len;
905         MBuf       *buf;
906
907         data = PG_GETARG_BYTEA_P(0);
908         buf = create_mbuf_from_vardata(data);
909         res = palloc(VARHDRSZ + 17);
910
911         res_len = pgp_get_keyid(buf, VARDATA(res));
912         mbuf_free(buf);
913         if (res_len < 0)
914                 ereport(ERROR,
915                                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
916                                  errmsg("%s", px_strerror(res_len))));
917         SET_VARSIZE(res, VARHDRSZ + res_len);
918
919         PG_FREE_IF_COPY(data, 0);
920         PG_RETURN_TEXT_P(res);
921 }