3 * PostgreSQL wrappers for pgp.
5 * Copyright (c) 2005 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
35 #include "parser/scansup.h"
36 #include "mb/pg_wchar.h"
37 #include "utils/builtins.h"
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
);
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
);
56 Datum
pgp_key_id_w(PG_FUNCTION_ARGS
);
58 Datum
pg_armor(PG_FUNCTION_ARGS
);
59 Datum
pg_dearmor(PG_FUNCTION_ARGS
);
61 /* function headers */
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
);
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
);
73 PG_FUNCTION_INFO_V1(pgp_key_id_w
);
75 PG_FUNCTION_INFO_V1(pg_armor
);
76 PG_FUNCTION_INFO_V1(pg_dearmor
);
79 * Mix a block of data into RNG.
82 add_block_entropy(PX_MD
*md
, text
*data
)
87 px_md_update(md
, (uint8
*) VARDATA(data
), VARSIZE(data
) - VARHDRSZ
);
88 px_md_finish(md
, sha1
);
90 px_add_entropy(sha1
, 20);
96 * Mix user data into RNG. It is for user own interests to have
100 add_entropy(text
*data1
, text
*data2
, text
*data3
)
105 if (!data1
&& !data2
&& !data3
)
108 if (px_get_random_bytes(rnd
, 3) < 0)
111 if (px_find_digest("sha1", &md
) < 0)
115 * Try to make the feeding unpredictable.
117 * Prefer data over keys, as it's rather likely that key is same in
122 if (data1
&& rnd
[0] >= 32)
123 add_block_entropy(md
, data1
);
126 if (data2
&& rnd
[1] >= 160)
127 add_block_entropy(md
, data2
);
130 if (data3
&& rnd
[2] >= 160)
131 add_block_entropy(md
, data3
);
134 memset(rnd
, 0, sizeof(rnd
));
138 * returns src in case of no conversion or error
141 convert_charset(text
*src
, int cset_from
, int cset_to
)
143 int src_len
= VARSIZE(src
) - VARHDRSZ
;
145 unsigned char *csrc
= (unsigned char *) VARDATA(src
);
148 dst
= pg_do_encoding_conversion(csrc
, src_len
, cset_from
, cset_to
);
152 res
= cstring_to_text((char *) dst
);
158 convert_from_utf8(text
*src
)
160 return convert_charset(src
, PG_UTF8
, GetDatabaseEncoding());
164 convert_to_utf8(text
*src
)
166 return convert_charset(src
, GetDatabaseEncoding(), PG_UTF8
);
170 clear_and_pfree(text
*p
)
172 memset(p
, 0, VARSIZE(p
));
177 * expect-* arguments storage
194 fill_expect(struct debug_expect
* ex
, int text_mode
)
198 ex
->cipher_algo
= -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;
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)))
213 #define EX_CHECK(arg) do { \
214 if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
218 check_expect(PGP_Context
*ctx
, struct debug_expect
* ex
)
220 EX_CHECK(cipher_algo
);
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
);
232 show_debug(const char *msg
)
234 ereport(NOTICE
, (errmsg("dbg: %s", msg
)));
238 set_arg(PGP_Context
*ctx
, char *key
, char *val
,
239 struct debug_expect
* ex
)
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
));
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)
269 ex
->cipher_algo
= pgp_get_cipher_code(val
);
271 else if (ex
!= NULL
&& strcmp(key
, "expect-disable-mdc") == 0)
274 ex
->disable_mdc
= atoi(val
);
276 else if (ex
!= NULL
&& strcmp(key
, "expect-sess-key") == 0)
279 ex
->use_sess_key
= atoi(val
);
281 else if (ex
!= NULL
&& strcmp(key
, "expect-s2k-mode") == 0)
284 ex
->s2k_mode
= atoi(val
);
286 else if (ex
!= NULL
&& strcmp(key
, "expect-s2k-digest-algo") == 0)
289 ex
->s2k_digest_algo
= pgp_get_digest_code(val
);
291 else if (ex
!= NULL
&& strcmp(key
, "expect-s2k-cipher-algo") == 0)
294 ex
->s2k_cipher_algo
= pgp_get_cipher_code(val
);
296 else if (ex
!= NULL
&& strcmp(key
, "expect-compress-algo") == 0)
299 ex
->compress_algo
= atoi(val
);
301 else if (ex
!= NULL
&& strcmp(key
, "expect-unicode-mode") == 0)
304 ex
->unicode_mode
= atoi(val
);
307 res
= PXE_ARGUMENT_ERROR
;
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.
318 getword(char *p
, char **res_p
, int *res_len
)
320 /* whitespace at start */
321 while (*p
&& (*p
== ' ' || *p
== '\t' || *p
== '\n'))
326 if (*p
== '=' || *p
== ',')
329 while (*p
&& !(*p
== ' ' || *p
== '\t' || *p
== '\n'
330 || *p
== '=' || *p
== ','))
334 *res_len
= p
- *res_p
;
336 /* whitespace at end */
337 while (*p
&& (*p
== ' ' || *p
== '\t' || *p
== '\n'))
344 * Convert to lowercase asciiz string.
347 downcase_convert(const uint8
*s
, int len
)
351 char *res
= palloc(len
+ 1);
353 for (i
= 0; i
< len
; i
++)
356 if (c
>= 'A' && c
<= 'Z')
365 parse_args(PGP_Context
*ctx
, uint8
*args
, int arg_len
,
366 struct debug_expect
* ex
)
368 char *str
= downcase_convert(args
, arg_len
);
378 res
= PXE_ARGUMENT_ERROR
;
379 p
= getword(p
, &key
, &key_len
);
382 p
= getword(p
, &val
, &val_len
);
385 else if (*p
++ != ',')
388 if (*key
== 0 || *val
== 0 || val_len
== 0)
394 res
= set_arg(ctx
, key
, val
, ex
);
403 create_mbuf_from_vardata(text
*data
)
405 return mbuf_create_from_data((uint8
*) VARDATA(data
),
406 VARSIZE(data
) - VARHDRSZ
);
410 init_work(PGP_Context
**ctx_p
, int is_text
,
411 text
*args
, struct debug_expect
* ex
)
413 int err
= pgp_init(ctx_p
);
415 fill_expect(ex
, is_text
);
417 if (err
== 0 && args
!= NULL
)
418 err
= parse_args(*ctx_p
, (uint8
*) VARDATA(args
),
419 VARSIZE(args
) - VARHDRSZ
, ex
);
424 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
425 errmsg("%s", px_strerror(err
))));
429 px_set_debug_handler(show_debug
);
431 pgp_set_text_mode(*ctx_p
, is_text
);
435 encrypt_internal(int is_pubenc
, int is_text
,
436 text
*data
, text
*key
, text
*args
)
446 struct debug_expect ex
;
447 text
*tmp_data
= NULL
;
450 * Add data and key info RNG.
452 add_entropy(data
, key
, NULL
);
454 init_work(&ctx
, is_text
, args
, &ex
);
456 if (is_text
&& pgp_get_unicode_mode(ctx
))
458 tmp_data
= convert_to_utf8(data
);
459 if (tmp_data
== data
)
465 src
= create_mbuf_from_vardata(data
);
466 dst
= mbuf_create(VARSIZE(data
) + 128);
469 * reserve room for header
471 mbuf_append(dst
, tmp
, VARHDRSZ
);
478 MBuf
*kbuf
= create_mbuf_from_vardata(key
);
480 err
= pgp_set_pubkey(ctx
, kbuf
,
485 err
= pgp_set_symkey(ctx
, (uint8
*) VARDATA(key
),
486 VARSIZE(key
) - VARHDRSZ
);
492 err
= pgp_encrypt(ctx
, src
, dst
);
500 px_set_debug_handler(NULL
);
502 clear_and_pfree(tmp_data
);
507 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
508 errmsg("%s", px_strerror(err
))));
511 /* res_len includes VARHDRSZ */
512 res_len
= mbuf_steal_data(dst
, &restmp
);
513 res
= (bytea
*) restmp
;
514 SET_VARSIZE(res
, res_len
);
517 clear_and_pfree(tmp_data
);
522 px_set_debug_handler(NULL
);
528 decrypt_internal(int is_pubenc
, int need_text
, text
*data
,
529 text
*key
, text
*keypsw
, text
*args
)
538 PGP_Context
*ctx
= NULL
;
539 struct debug_expect ex
;
543 init_work(&ctx
, need_text
, args
, &ex
);
545 src
= mbuf_create_from_data((uint8
*) VARDATA(data
),
546 VARSIZE(data
) - VARHDRSZ
);
547 dst
= mbuf_create(VARSIZE(data
) + 2048);
550 * reserve room for header
552 mbuf_append(dst
, tmp
, VARHDRSZ
);
565 psw
= (uint8
*) VARDATA(keypsw
);
566 psw_len
= VARSIZE(keypsw
) - VARHDRSZ
;
568 kbuf
= create_mbuf_from_vardata(key
);
569 err
= pgp_set_pubkey(ctx
, kbuf
, psw
, psw_len
, 1);
573 err
= pgp_set_symkey(ctx
, (uint8
*) VARDATA(key
),
574 VARSIZE(key
) - VARHDRSZ
);
580 err
= pgp_decrypt(ctx
, src
, dst
);
589 check_expect(ctx
, &ex
);
591 /* remember the setting */
592 got_unicode
= pgp_get_unicode_mode(ctx
);
602 px_set_debug_handler(NULL
);
606 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
607 errmsg("%s", px_strerror(err
))));
610 res_len
= mbuf_steal_data(dst
, &restmp
);
613 /* res_len includes VARHDRSZ */
614 res
= (bytea
*) restmp
;
615 SET_VARSIZE(res
, res_len
);
617 if (need_text
&& got_unicode
)
619 text
*utf
= convert_from_utf8(res
);
623 clear_and_pfree(res
);
627 px_set_debug_handler(NULL
);
630 * add successfull decryptions also into RNG
632 add_entropy(res
, key
, keypsw
);
638 * Wrappers for symmetric-key functions
641 pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS
)
648 data
= PG_GETARG_BYTEA_P(0);
649 key
= PG_GETARG_BYTEA_P(1);
651 arg
= PG_GETARG_BYTEA_P(2);
653 res
= encrypt_internal(0, 0, data
, key
, arg
);
655 PG_FREE_IF_COPY(data
, 0);
656 PG_FREE_IF_COPY(key
, 1);
658 PG_FREE_IF_COPY(arg
, 2);
659 PG_RETURN_TEXT_P(res
);
663 pgp_sym_encrypt_text(PG_FUNCTION_ARGS
)
670 data
= PG_GETARG_BYTEA_P(0);
671 key
= PG_GETARG_BYTEA_P(1);
673 arg
= PG_GETARG_BYTEA_P(2);
675 res
= encrypt_internal(0, 1, data
, key
, arg
);
677 PG_FREE_IF_COPY(data
, 0);
678 PG_FREE_IF_COPY(key
, 1);
680 PG_FREE_IF_COPY(arg
, 2);
681 PG_RETURN_TEXT_P(res
);
686 pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS
)
693 data
= PG_GETARG_BYTEA_P(0);
694 key
= PG_GETARG_BYTEA_P(1);
696 arg
= PG_GETARG_BYTEA_P(2);
698 res
= decrypt_internal(0, 0, data
, key
, NULL
, arg
);
700 PG_FREE_IF_COPY(data
, 0);
701 PG_FREE_IF_COPY(key
, 1);
703 PG_FREE_IF_COPY(arg
, 2);
704 PG_RETURN_TEXT_P(res
);
708 pgp_sym_decrypt_text(PG_FUNCTION_ARGS
)
715 data
= PG_GETARG_BYTEA_P(0);
716 key
= PG_GETARG_BYTEA_P(1);
718 arg
= PG_GETARG_BYTEA_P(2);
720 res
= decrypt_internal(0, 1, data
, key
, NULL
, arg
);
722 PG_FREE_IF_COPY(data
, 0);
723 PG_FREE_IF_COPY(key
, 1);
725 PG_FREE_IF_COPY(arg
, 2);
726 PG_RETURN_TEXT_P(res
);
730 * Wrappers for public-key functions
734 pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS
)
741 data
= PG_GETARG_BYTEA_P(0);
742 key
= PG_GETARG_BYTEA_P(1);
744 arg
= PG_GETARG_BYTEA_P(2);
746 res
= encrypt_internal(1, 0, data
, key
, arg
);
748 PG_FREE_IF_COPY(data
, 0);
749 PG_FREE_IF_COPY(key
, 1);
751 PG_FREE_IF_COPY(arg
, 2);
752 PG_RETURN_TEXT_P(res
);
756 pgp_pub_encrypt_text(PG_FUNCTION_ARGS
)
763 data
= PG_GETARG_BYTEA_P(0);
764 key
= PG_GETARG_BYTEA_P(1);
766 arg
= PG_GETARG_BYTEA_P(2);
768 res
= encrypt_internal(1, 1, data
, key
, arg
);
770 PG_FREE_IF_COPY(data
, 0);
771 PG_FREE_IF_COPY(key
, 1);
773 PG_FREE_IF_COPY(arg
, 2);
774 PG_RETURN_TEXT_P(res
);
779 pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS
)
787 data
= PG_GETARG_BYTEA_P(0);
788 key
= PG_GETARG_BYTEA_P(1);
790 psw
= PG_GETARG_BYTEA_P(2);
792 arg
= PG_GETARG_BYTEA_P(3);
794 res
= decrypt_internal(1, 0, data
, key
, psw
, arg
);
796 PG_FREE_IF_COPY(data
, 0);
797 PG_FREE_IF_COPY(key
, 1);
799 PG_FREE_IF_COPY(psw
, 2);
801 PG_FREE_IF_COPY(arg
, 3);
802 PG_RETURN_TEXT_P(res
);
806 pgp_pub_decrypt_text(PG_FUNCTION_ARGS
)
814 data
= PG_GETARG_BYTEA_P(0);
815 key
= PG_GETARG_BYTEA_P(1);
817 psw
= PG_GETARG_BYTEA_P(2);
819 arg
= PG_GETARG_BYTEA_P(3);
821 res
= decrypt_internal(1, 1, data
, key
, psw
, arg
);
823 PG_FREE_IF_COPY(data
, 0);
824 PG_FREE_IF_COPY(key
, 1);
826 PG_FREE_IF_COPY(psw
, 2);
828 PG_FREE_IF_COPY(arg
, 3);
829 PG_RETURN_TEXT_P(res
);
834 * Wrappers for PGP ascii armor
838 pg_armor(PG_FUNCTION_ARGS
)
846 data
= PG_GETARG_BYTEA_P(0);
847 data_len
= VARSIZE(data
) - VARHDRSZ
;
849 guess_len
= pgp_armor_enc_len(data_len
);
850 res
= palloc(VARHDRSZ
+ guess_len
);
852 res_len
= pgp_armor_encode((uint8
*) VARDATA(data
), data_len
,
853 (uint8
*) VARDATA(res
));
854 if (res_len
> guess_len
)
856 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
857 errmsg("Overflow - encode estimate too small")));
858 SET_VARSIZE(res
, VARHDRSZ
+ res_len
);
860 PG_FREE_IF_COPY(data
, 0);
861 PG_RETURN_TEXT_P(res
);
865 pg_dearmor(PG_FUNCTION_ARGS
)
873 data
= PG_GETARG_TEXT_P(0);
874 data_len
= VARSIZE(data
) - VARHDRSZ
;
876 guess_len
= pgp_armor_dec_len(data_len
);
877 res
= palloc(VARHDRSZ
+ guess_len
);
879 res_len
= pgp_armor_decode((uint8
*) VARDATA(data
), data_len
,
880 (uint8
*) VARDATA(res
));
883 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
884 errmsg("%s", px_strerror(res_len
))));
885 if (res_len
> guess_len
)
887 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
888 errmsg("Overflow - decode estimate too small")));
889 SET_VARSIZE(res
, VARHDRSZ
+ res_len
);
891 PG_FREE_IF_COPY(data
, 0);
892 PG_RETURN_TEXT_P(res
);
896 * Wrappers for PGP key id
900 pgp_key_id_w(PG_FUNCTION_ARGS
)
907 data
= PG_GETARG_BYTEA_P(0);
908 buf
= create_mbuf_from_vardata(data
);
909 res
= palloc(VARHDRSZ
+ 17);
911 res_len
= pgp_get_keyid(buf
, VARDATA(res
));
915 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
916 errmsg("%s", px_strerror(res_len
))));
917 SET_VARSIZE(res
, VARHDRSZ
+ res_len
);
919 PG_FREE_IF_COPY(data
, 0);
920 PG_RETURN_TEXT_P(res
);