Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-pgsql.c

Go to the documentation of this file.
00001 /*
00002  * pgp-pgsql.c
00003  *      PostgreSQL wrappers for pgp.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-pgsql.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "mb/pg_wchar.h"
00035 #include "utils/builtins.h"
00036 
00037 #include "mbuf.h"
00038 #include "px.h"
00039 #include "pgp.h"
00040 
00041 /*
00042  * public functions
00043  */
00044 Datum       pgp_sym_encrypt_text(PG_FUNCTION_ARGS);
00045 Datum       pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS);
00046 Datum       pgp_sym_decrypt_text(PG_FUNCTION_ARGS);
00047 Datum       pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS);
00048 
00049 Datum       pgp_pub_encrypt_text(PG_FUNCTION_ARGS);
00050 Datum       pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS);
00051 Datum       pgp_pub_decrypt_text(PG_FUNCTION_ARGS);
00052 Datum       pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS);
00053 
00054 Datum       pgp_key_id_w(PG_FUNCTION_ARGS);
00055 
00056 Datum       pg_armor(PG_FUNCTION_ARGS);
00057 Datum       pg_dearmor(PG_FUNCTION_ARGS);
00058 
00059 /* function headers */
00060 
00061 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_bytea);
00062 PG_FUNCTION_INFO_V1(pgp_sym_encrypt_text);
00063 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_bytea);
00064 PG_FUNCTION_INFO_V1(pgp_sym_decrypt_text);
00065 
00066 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_bytea);
00067 PG_FUNCTION_INFO_V1(pgp_pub_encrypt_text);
00068 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_bytea);
00069 PG_FUNCTION_INFO_V1(pgp_pub_decrypt_text);
00070 
00071 PG_FUNCTION_INFO_V1(pgp_key_id_w);
00072 
00073 PG_FUNCTION_INFO_V1(pg_armor);
00074 PG_FUNCTION_INFO_V1(pg_dearmor);
00075 
00076 /*
00077  * Mix a block of data into RNG.
00078  */
00079 static void
00080 add_block_entropy(PX_MD *md, text *data)
00081 {
00082     uint8       sha1[20];
00083 
00084     px_md_reset(md);
00085     px_md_update(md, (uint8 *) VARDATA(data), VARSIZE(data) - VARHDRSZ);
00086     px_md_finish(md, sha1);
00087 
00088     px_add_entropy(sha1, 20);
00089 
00090     memset(sha1, 0, 20);
00091 }
00092 
00093 /*
00094  * Mix user data into RNG.  It is for user own interests to have
00095  * RNG state shuffled.
00096  */
00097 static void
00098 add_entropy(text *data1, text *data2, text *data3)
00099 {
00100     PX_MD      *md;
00101     uint8       rnd[3];
00102 
00103     if (!data1 && !data2 && !data3)
00104         return;
00105 
00106     if (px_get_random_bytes(rnd, 3) < 0)
00107         return;
00108 
00109     if (px_find_digest("sha1", &md) < 0)
00110         return;
00111 
00112     /*
00113      * Try to make the feeding unpredictable.
00114      *
00115      * Prefer data over keys, as it's rather likely that key is same in
00116      * several calls.
00117      */
00118 
00119     /* chance: 7/8 */
00120     if (data1 && rnd[0] >= 32)
00121         add_block_entropy(md, data1);
00122 
00123     /* chance: 5/8 */
00124     if (data2 && rnd[1] >= 160)
00125         add_block_entropy(md, data2);
00126 
00127     /* chance: 5/8 */
00128     if (data3 && rnd[2] >= 160)
00129         add_block_entropy(md, data3);
00130 
00131     px_md_free(md);
00132     memset(rnd, 0, sizeof(rnd));
00133 }
00134 
00135 /*
00136  * returns src in case of no conversion or error
00137  */
00138 static text *
00139 convert_charset(text *src, int cset_from, int cset_to)
00140 {
00141     int         src_len = VARSIZE(src) - VARHDRSZ;
00142     unsigned char *dst;
00143     unsigned char *csrc = (unsigned char *) VARDATA(src);
00144     text       *res;
00145 
00146     dst = pg_do_encoding_conversion(csrc, src_len, cset_from, cset_to);
00147     if (dst == csrc)
00148         return src;
00149 
00150     res = cstring_to_text((char *) dst);
00151     pfree(dst);
00152     return res;
00153 }
00154 
00155 static text *
00156 convert_from_utf8(text *src)
00157 {
00158     return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
00159 }
00160 
00161 static text *
00162 convert_to_utf8(text *src)
00163 {
00164     return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
00165 }
00166 
00167 static void
00168 clear_and_pfree(text *p)
00169 {
00170     memset(p, 0, VARSIZE(p));
00171     pfree(p);
00172 }
00173 
00174 /*
00175  * expect-* arguments storage
00176  */
00177 struct debug_expect
00178 {
00179     int         debug;
00180     int         expect;
00181     int         cipher_algo;
00182     int         s2k_mode;
00183     int         s2k_cipher_algo;
00184     int         s2k_digest_algo;
00185     int         compress_algo;
00186     int         use_sess_key;
00187     int         disable_mdc;
00188     int         unicode_mode;
00189 };
00190 
00191 static void
00192 fill_expect(struct debug_expect * ex, int text_mode)
00193 {
00194     ex->debug = 0;
00195     ex->expect = 0;
00196     ex->cipher_algo = -1;
00197     ex->s2k_mode = -1;
00198     ex->s2k_cipher_algo = -1;
00199     ex->s2k_digest_algo = -1;
00200     ex->compress_algo = -1;
00201     ex->use_sess_key = -1;
00202     ex->disable_mdc = -1;
00203     ex->unicode_mode = -1;
00204 }
00205 
00206 #define EX_MSG(arg) \
00207     ereport(NOTICE, (errmsg( \
00208         "pgp_decrypt: unexpected %s: expected %d got %d", \
00209         CppAsString(arg), ex->arg, ctx->arg)))
00210 
00211 #define EX_CHECK(arg) do { \
00212         if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
00213     } while (0)
00214 
00215 static void
00216 check_expect(PGP_Context *ctx, struct debug_expect * ex)
00217 {
00218     EX_CHECK(cipher_algo);
00219     EX_CHECK(s2k_mode);
00220     EX_CHECK(s2k_digest_algo);
00221     EX_CHECK(use_sess_key);
00222     if (ctx->use_sess_key)
00223         EX_CHECK(s2k_cipher_algo);
00224     EX_CHECK(disable_mdc);
00225     EX_CHECK(compress_algo);
00226     EX_CHECK(unicode_mode);
00227 }
00228 
00229 static void
00230 show_debug(const char *msg)
00231 {
00232     ereport(NOTICE, (errmsg("dbg: %s", msg)));
00233 }
00234 
00235 static int
00236 set_arg(PGP_Context *ctx, char *key, char *val,
00237         struct debug_expect * ex)
00238 {
00239     int         res = 0;
00240 
00241     if (strcmp(key, "cipher-algo") == 0)
00242         res = pgp_set_cipher_algo(ctx, val);
00243     else if (strcmp(key, "disable-mdc") == 0)
00244         res = pgp_disable_mdc(ctx, atoi(val));
00245     else if (strcmp(key, "sess-key") == 0)
00246         res = pgp_set_sess_key(ctx, atoi(val));
00247     else if (strcmp(key, "s2k-mode") == 0)
00248         res = pgp_set_s2k_mode(ctx, atoi(val));
00249     else if (strcmp(key, "s2k-digest-algo") == 0)
00250         res = pgp_set_s2k_digest_algo(ctx, val);
00251     else if (strcmp(key, "s2k-cipher-algo") == 0)
00252         res = pgp_set_s2k_cipher_algo(ctx, val);
00253     else if (strcmp(key, "compress-algo") == 0)
00254         res = pgp_set_compress_algo(ctx, atoi(val));
00255     else if (strcmp(key, "compress-level") == 0)
00256         res = pgp_set_compress_level(ctx, atoi(val));
00257     else if (strcmp(key, "convert-crlf") == 0)
00258         res = pgp_set_convert_crlf(ctx, atoi(val));
00259     else if (strcmp(key, "unicode-mode") == 0)
00260         res = pgp_set_unicode_mode(ctx, atoi(val));
00261     /* decrypt debug */
00262     else if (ex != NULL && strcmp(key, "debug") == 0)
00263         ex->debug = atoi(val);
00264     else if (ex != NULL && strcmp(key, "expect-cipher-algo") == 0)
00265     {
00266         ex->expect = 1;
00267         ex->cipher_algo = pgp_get_cipher_code(val);
00268     }
00269     else if (ex != NULL && strcmp(key, "expect-disable-mdc") == 0)
00270     {
00271         ex->expect = 1;
00272         ex->disable_mdc = atoi(val);
00273     }
00274     else if (ex != NULL && strcmp(key, "expect-sess-key") == 0)
00275     {
00276         ex->expect = 1;
00277         ex->use_sess_key = atoi(val);
00278     }
00279     else if (ex != NULL && strcmp(key, "expect-s2k-mode") == 0)
00280     {
00281         ex->expect = 1;
00282         ex->s2k_mode = atoi(val);
00283     }
00284     else if (ex != NULL && strcmp(key, "expect-s2k-digest-algo") == 0)
00285     {
00286         ex->expect = 1;
00287         ex->s2k_digest_algo = pgp_get_digest_code(val);
00288     }
00289     else if (ex != NULL && strcmp(key, "expect-s2k-cipher-algo") == 0)
00290     {
00291         ex->expect = 1;
00292         ex->s2k_cipher_algo = pgp_get_cipher_code(val);
00293     }
00294     else if (ex != NULL && strcmp(key, "expect-compress-algo") == 0)
00295     {
00296         ex->expect = 1;
00297         ex->compress_algo = atoi(val);
00298     }
00299     else if (ex != NULL && strcmp(key, "expect-unicode-mode") == 0)
00300     {
00301         ex->expect = 1;
00302         ex->unicode_mode = atoi(val);
00303     }
00304     else
00305         res = PXE_ARGUMENT_ERROR;
00306 
00307     return res;
00308 }
00309 
00310 /*
00311  * Find next word.  Handle ',' and '=' as words.  Skip whitespace.
00312  * Put word info into res_p, res_len.
00313  * Returns ptr to next word.
00314  */
00315 static char *
00316 getword(char *p, char **res_p, int *res_len)
00317 {
00318     /* whitespace at start */
00319     while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
00320         p++;
00321 
00322     /* word data */
00323     *res_p = p;
00324     if (*p == '=' || *p == ',')
00325         p++;
00326     else
00327         while (*p && !(*p == ' ' || *p == '\t' || *p == '\n'
00328                        || *p == '=' || *p == ','))
00329             p++;
00330 
00331     /* word end */
00332     *res_len = p - *res_p;
00333 
00334     /* whitespace at end */
00335     while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
00336         p++;
00337 
00338     return p;
00339 }
00340 
00341 /*
00342  * Convert to lowercase asciiz string.
00343  */
00344 static char *
00345 downcase_convert(const uint8 *s, int len)
00346 {
00347     int         c,
00348                 i;
00349     char       *res = palloc(len + 1);
00350 
00351     for (i = 0; i < len; i++)
00352     {
00353         c = s[i];
00354         if (c >= 'A' && c <= 'Z')
00355             c += 'a' - 'A';
00356         res[i] = c;
00357     }
00358     res[len] = 0;
00359     return res;
00360 }
00361 
00362 static int
00363 parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
00364            struct debug_expect * ex)
00365 {
00366     char       *str = downcase_convert(args, arg_len);
00367     char       *key,
00368                *val;
00369     int         key_len,
00370                 val_len;
00371     int         res = 0;
00372     char       *p = str;
00373 
00374     while (*p)
00375     {
00376         res = PXE_ARGUMENT_ERROR;
00377         p = getword(p, &key, &key_len);
00378         if (*p++ != '=')
00379             break;
00380         p = getword(p, &val, &val_len);
00381         if (*p == '\0')
00382             ;
00383         else if (*p++ != ',')
00384             break;
00385 
00386         if (*key == 0 || *val == 0 || val_len == 0)
00387             break;
00388 
00389         key[key_len] = 0;
00390         val[val_len] = 0;
00391 
00392         res = set_arg(ctx, key, val, ex);
00393         if (res < 0)
00394             break;
00395     }
00396     pfree(str);
00397     return res;
00398 }
00399 
00400 static MBuf *
00401 create_mbuf_from_vardata(text *data)
00402 {
00403     return mbuf_create_from_data((uint8 *) VARDATA(data),
00404                                  VARSIZE(data) - VARHDRSZ);
00405 }
00406 
00407 static void
00408 init_work(PGP_Context **ctx_p, int is_text,
00409           text *args, struct debug_expect * ex)
00410 {
00411     int         err = pgp_init(ctx_p);
00412 
00413     fill_expect(ex, is_text);
00414 
00415     if (err == 0 && args != NULL)
00416         err = parse_args(*ctx_p, (uint8 *) VARDATA(args),
00417                          VARSIZE(args) - VARHDRSZ, ex);
00418 
00419     if (err)
00420     {
00421         ereport(ERROR,
00422                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00423                  errmsg("%s", px_strerror(err))));
00424     }
00425 
00426     if (ex->debug)
00427         px_set_debug_handler(show_debug);
00428 
00429     pgp_set_text_mode(*ctx_p, is_text);
00430 }
00431 
00432 static bytea *
00433 encrypt_internal(int is_pubenc, int is_text,
00434                  text *data, text *key, text *args)
00435 {
00436     MBuf       *src,
00437                *dst;
00438     uint8       tmp[VARHDRSZ];
00439     uint8      *restmp;
00440     bytea      *res;
00441     int         res_len;
00442     PGP_Context *ctx;
00443     int         err;
00444     struct debug_expect ex;
00445     text       *tmp_data = NULL;
00446 
00447     /*
00448      * Add data and key info RNG.
00449      */
00450     add_entropy(data, key, NULL);
00451 
00452     init_work(&ctx, is_text, args, &ex);
00453 
00454     if (is_text && pgp_get_unicode_mode(ctx))
00455     {
00456         tmp_data = convert_to_utf8(data);
00457         if (tmp_data == data)
00458             tmp_data = NULL;
00459         else
00460             data = tmp_data;
00461     }
00462 
00463     src = create_mbuf_from_vardata(data);
00464     dst = mbuf_create(VARSIZE(data) + 128);
00465 
00466     /*
00467      * reserve room for header
00468      */
00469     mbuf_append(dst, tmp, VARHDRSZ);
00470 
00471     /*
00472      * set key
00473      */
00474     if (is_pubenc)
00475     {
00476         MBuf       *kbuf = create_mbuf_from_vardata(key);
00477 
00478         err = pgp_set_pubkey(ctx, kbuf,
00479                              NULL, 0, 0);
00480         mbuf_free(kbuf);
00481     }
00482     else
00483         err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
00484                              VARSIZE(key) - VARHDRSZ);
00485 
00486     /*
00487      * encrypt
00488      */
00489     if (err >= 0)
00490         err = pgp_encrypt(ctx, src, dst);
00491 
00492     /*
00493      * check for error
00494      */
00495     if (err)
00496     {
00497         if (ex.debug)
00498             px_set_debug_handler(NULL);
00499         if (tmp_data)
00500             clear_and_pfree(tmp_data);
00501         pgp_free(ctx);
00502         mbuf_free(src);
00503         mbuf_free(dst);
00504         ereport(ERROR,
00505                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00506                  errmsg("%s", px_strerror(err))));
00507     }
00508 
00509     /* res_len includes VARHDRSZ */
00510     res_len = mbuf_steal_data(dst, &restmp);
00511     res = (bytea *) restmp;
00512     SET_VARSIZE(res, res_len);
00513 
00514     if (tmp_data)
00515         clear_and_pfree(tmp_data);
00516     pgp_free(ctx);
00517     mbuf_free(src);
00518     mbuf_free(dst);
00519 
00520     px_set_debug_handler(NULL);
00521 
00522     return res;
00523 }
00524 
00525 static bytea *
00526 decrypt_internal(int is_pubenc, int need_text, text *data,
00527                  text *key, text *keypsw, text *args)
00528 {
00529     int         err;
00530     MBuf       *src = NULL,
00531                *dst = NULL;
00532     uint8       tmp[VARHDRSZ];
00533     uint8      *restmp;
00534     bytea      *res;
00535     int         res_len;
00536     PGP_Context *ctx = NULL;
00537     struct debug_expect ex;
00538     int         got_unicode = 0;
00539 
00540 
00541     init_work(&ctx, need_text, args, &ex);
00542 
00543     src = mbuf_create_from_data((uint8 *) VARDATA(data),
00544                                 VARSIZE(data) - VARHDRSZ);
00545     dst = mbuf_create(VARSIZE(data) + 2048);
00546 
00547     /*
00548      * reserve room for header
00549      */
00550     mbuf_append(dst, tmp, VARHDRSZ);
00551 
00552     /*
00553      * set key
00554      */
00555     if (is_pubenc)
00556     {
00557         uint8      *psw = NULL;
00558         int         psw_len = 0;
00559         MBuf       *kbuf;
00560 
00561         if (keypsw)
00562         {
00563             psw = (uint8 *) VARDATA(keypsw);
00564             psw_len = VARSIZE(keypsw) - VARHDRSZ;
00565         }
00566         kbuf = create_mbuf_from_vardata(key);
00567         err = pgp_set_pubkey(ctx, kbuf, psw, psw_len, 1);
00568         mbuf_free(kbuf);
00569     }
00570     else
00571         err = pgp_set_symkey(ctx, (uint8 *) VARDATA(key),
00572                              VARSIZE(key) - VARHDRSZ);
00573 
00574     /*
00575      * decrypt
00576      */
00577     if (err >= 0)
00578         err = pgp_decrypt(ctx, src, dst);
00579 
00580     /*
00581      * failed?
00582      */
00583     if (err < 0)
00584         goto out;
00585 
00586     if (ex.expect)
00587         check_expect(ctx, &ex);
00588 
00589     /* remember the setting */
00590     got_unicode = pgp_get_unicode_mode(ctx);
00591 
00592 out:
00593     if (src)
00594         mbuf_free(src);
00595     if (ctx)
00596         pgp_free(ctx);
00597 
00598     if (err)
00599     {
00600         px_set_debug_handler(NULL);
00601         if (dst)
00602             mbuf_free(dst);
00603         ereport(ERROR,
00604                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00605                  errmsg("%s", px_strerror(err))));
00606     }
00607 
00608     res_len = mbuf_steal_data(dst, &restmp);
00609     mbuf_free(dst);
00610 
00611     /* res_len includes VARHDRSZ */
00612     res = (bytea *) restmp;
00613     SET_VARSIZE(res, res_len);
00614 
00615     if (need_text && got_unicode)
00616     {
00617         text       *utf = convert_from_utf8(res);
00618 
00619         if (utf != res)
00620         {
00621             clear_and_pfree(res);
00622             res = utf;
00623         }
00624     }
00625     px_set_debug_handler(NULL);
00626 
00627     /*
00628      * add successful decryptions also into RNG
00629      */
00630     add_entropy(res, key, keypsw);
00631 
00632     return res;
00633 }
00634 
00635 /*
00636  * Wrappers for symmetric-key functions
00637  */
00638 Datum
00639 pgp_sym_encrypt_bytea(PG_FUNCTION_ARGS)
00640 {
00641     bytea      *data,
00642                *key;
00643     text       *arg = NULL;
00644     text       *res;
00645 
00646     data = PG_GETARG_BYTEA_P(0);
00647     key = PG_GETARG_BYTEA_P(1);
00648     if (PG_NARGS() > 2)
00649         arg = PG_GETARG_BYTEA_P(2);
00650 
00651     res = encrypt_internal(0, 0, data, key, arg);
00652 
00653     PG_FREE_IF_COPY(data, 0);
00654     PG_FREE_IF_COPY(key, 1);
00655     if (PG_NARGS() > 2)
00656         PG_FREE_IF_COPY(arg, 2);
00657     PG_RETURN_TEXT_P(res);
00658 }
00659 
00660 Datum
00661 pgp_sym_encrypt_text(PG_FUNCTION_ARGS)
00662 {
00663     bytea      *data,
00664                *key;
00665     text       *arg = NULL;
00666     text       *res;
00667 
00668     data = PG_GETARG_BYTEA_P(0);
00669     key = PG_GETARG_BYTEA_P(1);
00670     if (PG_NARGS() > 2)
00671         arg = PG_GETARG_BYTEA_P(2);
00672 
00673     res = encrypt_internal(0, 1, data, key, arg);
00674 
00675     PG_FREE_IF_COPY(data, 0);
00676     PG_FREE_IF_COPY(key, 1);
00677     if (PG_NARGS() > 2)
00678         PG_FREE_IF_COPY(arg, 2);
00679     PG_RETURN_TEXT_P(res);
00680 }
00681 
00682 
00683 Datum
00684 pgp_sym_decrypt_bytea(PG_FUNCTION_ARGS)
00685 {
00686     bytea      *data,
00687                *key;
00688     text       *arg = NULL;
00689     text       *res;
00690 
00691     data = PG_GETARG_BYTEA_P(0);
00692     key = PG_GETARG_BYTEA_P(1);
00693     if (PG_NARGS() > 2)
00694         arg = PG_GETARG_BYTEA_P(2);
00695 
00696     res = decrypt_internal(0, 0, data, key, NULL, arg);
00697 
00698     PG_FREE_IF_COPY(data, 0);
00699     PG_FREE_IF_COPY(key, 1);
00700     if (PG_NARGS() > 2)
00701         PG_FREE_IF_COPY(arg, 2);
00702     PG_RETURN_TEXT_P(res);
00703 }
00704 
00705 Datum
00706 pgp_sym_decrypt_text(PG_FUNCTION_ARGS)
00707 {
00708     bytea      *data,
00709                *key;
00710     text       *arg = NULL;
00711     text       *res;
00712 
00713     data = PG_GETARG_BYTEA_P(0);
00714     key = PG_GETARG_BYTEA_P(1);
00715     if (PG_NARGS() > 2)
00716         arg = PG_GETARG_BYTEA_P(2);
00717 
00718     res = decrypt_internal(0, 1, data, key, NULL, arg);
00719 
00720     PG_FREE_IF_COPY(data, 0);
00721     PG_FREE_IF_COPY(key, 1);
00722     if (PG_NARGS() > 2)
00723         PG_FREE_IF_COPY(arg, 2);
00724     PG_RETURN_TEXT_P(res);
00725 }
00726 
00727 /*
00728  * Wrappers for public-key functions
00729  */
00730 
00731 Datum
00732 pgp_pub_encrypt_bytea(PG_FUNCTION_ARGS)
00733 {
00734     bytea      *data,
00735                *key;
00736     text       *arg = NULL;
00737     text       *res;
00738 
00739     data = PG_GETARG_BYTEA_P(0);
00740     key = PG_GETARG_BYTEA_P(1);
00741     if (PG_NARGS() > 2)
00742         arg = PG_GETARG_BYTEA_P(2);
00743 
00744     res = encrypt_internal(1, 0, data, key, arg);
00745 
00746     PG_FREE_IF_COPY(data, 0);
00747     PG_FREE_IF_COPY(key, 1);
00748     if (PG_NARGS() > 2)
00749         PG_FREE_IF_COPY(arg, 2);
00750     PG_RETURN_TEXT_P(res);
00751 }
00752 
00753 Datum
00754 pgp_pub_encrypt_text(PG_FUNCTION_ARGS)
00755 {
00756     bytea      *data,
00757                *key;
00758     text       *arg = NULL;
00759     text       *res;
00760 
00761     data = PG_GETARG_BYTEA_P(0);
00762     key = PG_GETARG_BYTEA_P(1);
00763     if (PG_NARGS() > 2)
00764         arg = PG_GETARG_BYTEA_P(2);
00765 
00766     res = encrypt_internal(1, 1, data, key, arg);
00767 
00768     PG_FREE_IF_COPY(data, 0);
00769     PG_FREE_IF_COPY(key, 1);
00770     if (PG_NARGS() > 2)
00771         PG_FREE_IF_COPY(arg, 2);
00772     PG_RETURN_TEXT_P(res);
00773 }
00774 
00775 
00776 Datum
00777 pgp_pub_decrypt_bytea(PG_FUNCTION_ARGS)
00778 {
00779     bytea      *data,
00780                *key;
00781     text       *psw = NULL,
00782                *arg = NULL;
00783     text       *res;
00784 
00785     data = PG_GETARG_BYTEA_P(0);
00786     key = PG_GETARG_BYTEA_P(1);
00787     if (PG_NARGS() > 2)
00788         psw = PG_GETARG_BYTEA_P(2);
00789     if (PG_NARGS() > 3)
00790         arg = PG_GETARG_BYTEA_P(3);
00791 
00792     res = decrypt_internal(1, 0, data, key, psw, arg);
00793 
00794     PG_FREE_IF_COPY(data, 0);
00795     PG_FREE_IF_COPY(key, 1);
00796     if (PG_NARGS() > 2)
00797         PG_FREE_IF_COPY(psw, 2);
00798     if (PG_NARGS() > 3)
00799         PG_FREE_IF_COPY(arg, 3);
00800     PG_RETURN_TEXT_P(res);
00801 }
00802 
00803 Datum
00804 pgp_pub_decrypt_text(PG_FUNCTION_ARGS)
00805 {
00806     bytea      *data,
00807                *key;
00808     text       *psw = NULL,
00809                *arg = NULL;
00810     text       *res;
00811 
00812     data = PG_GETARG_BYTEA_P(0);
00813     key = PG_GETARG_BYTEA_P(1);
00814     if (PG_NARGS() > 2)
00815         psw = PG_GETARG_BYTEA_P(2);
00816     if (PG_NARGS() > 3)
00817         arg = PG_GETARG_BYTEA_P(3);
00818 
00819     res = decrypt_internal(1, 1, data, key, psw, arg);
00820 
00821     PG_FREE_IF_COPY(data, 0);
00822     PG_FREE_IF_COPY(key, 1);
00823     if (PG_NARGS() > 2)
00824         PG_FREE_IF_COPY(psw, 2);
00825     if (PG_NARGS() > 3)
00826         PG_FREE_IF_COPY(arg, 3);
00827     PG_RETURN_TEXT_P(res);
00828 }
00829 
00830 
00831 /*
00832  * Wrappers for PGP ascii armor
00833  */
00834 
00835 Datum
00836 pg_armor(PG_FUNCTION_ARGS)
00837 {
00838     bytea      *data;
00839     text       *res;
00840     int         data_len,
00841                 res_len,
00842                 guess_len;
00843 
00844     data = PG_GETARG_BYTEA_P(0);
00845     data_len = VARSIZE(data) - VARHDRSZ;
00846 
00847     guess_len = pgp_armor_enc_len(data_len);
00848     res = palloc(VARHDRSZ + guess_len);
00849 
00850     res_len = pgp_armor_encode((uint8 *) VARDATA(data), data_len,
00851                                (uint8 *) VARDATA(res));
00852     if (res_len > guess_len)
00853         ereport(ERROR,
00854                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00855                  errmsg("Overflow - encode estimate too small")));
00856     SET_VARSIZE(res, VARHDRSZ + res_len);
00857 
00858     PG_FREE_IF_COPY(data, 0);
00859     PG_RETURN_TEXT_P(res);
00860 }
00861 
00862 Datum
00863 pg_dearmor(PG_FUNCTION_ARGS)
00864 {
00865     text       *data;
00866     bytea      *res;
00867     int         data_len,
00868                 res_len,
00869                 guess_len;
00870 
00871     data = PG_GETARG_TEXT_P(0);
00872     data_len = VARSIZE(data) - VARHDRSZ;
00873 
00874     guess_len = pgp_armor_dec_len(data_len);
00875     res = palloc(VARHDRSZ + guess_len);
00876 
00877     res_len = pgp_armor_decode((uint8 *) VARDATA(data), data_len,
00878                                (uint8 *) VARDATA(res));
00879     if (res_len < 0)
00880         ereport(ERROR,
00881                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00882                  errmsg("%s", px_strerror(res_len))));
00883     if (res_len > guess_len)
00884         ereport(ERROR,
00885                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00886                  errmsg("Overflow - decode estimate too small")));
00887     SET_VARSIZE(res, VARHDRSZ + res_len);
00888 
00889     PG_FREE_IF_COPY(data, 0);
00890     PG_RETURN_TEXT_P(res);
00891 }
00892 
00893 /*
00894  * Wrappers for PGP key id
00895  */
00896 
00897 Datum
00898 pgp_key_id_w(PG_FUNCTION_ARGS)
00899 {
00900     bytea      *data;
00901     text       *res;
00902     int         res_len;
00903     MBuf       *buf;
00904 
00905     data = PG_GETARG_BYTEA_P(0);
00906     buf = create_mbuf_from_vardata(data);
00907     res = palloc(VARHDRSZ + 17);
00908 
00909     res_len = pgp_get_keyid(buf, VARDATA(res));
00910     mbuf_free(buf);
00911     if (res_len < 0)
00912         ereport(ERROR,
00913                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00914                  errmsg("%s", px_strerror(res_len))));
00915     SET_VARSIZE(res, VARHDRSZ + res_len);
00916 
00917     PG_FREE_IF_COPY(data, 0);
00918     PG_RETURN_TEXT_P(res);
00919 }