Header And Logo

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

pgcrypto.c

Go to the documentation of this file.
00001 /*
00002  * pgcrypto.c
00003  *      Various cryptographic stuff for PostgreSQL.
00004  *
00005  * Copyright (c) 2001 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/pgcrypto.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include <ctype.h>
00035 
00036 #include "parser/scansup.h"
00037 #include "utils/builtins.h"
00038 
00039 #include "px.h"
00040 #include "px-crypt.h"
00041 #include "pgcrypto.h"
00042 
00043 PG_MODULE_MAGIC;
00044 
00045 /* private stuff */
00046 
00047 typedef int (*PFN) (const char *name, void **res);
00048 static void *find_provider(text *name, PFN pf, char *desc, int silent);
00049 
00050 /* SQL function: hash(bytea, text) returns bytea */
00051 PG_FUNCTION_INFO_V1(pg_digest);
00052 
00053 Datum
00054 pg_digest(PG_FUNCTION_ARGS)
00055 {
00056     bytea      *arg;
00057     text       *name;
00058     unsigned    len,
00059                 hlen;
00060     PX_MD      *md;
00061     bytea      *res;
00062 
00063     name = PG_GETARG_TEXT_P(1);
00064 
00065     /* will give error if fails */
00066     md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
00067 
00068     hlen = px_md_result_size(md);
00069 
00070     res = (text *) palloc(hlen + VARHDRSZ);
00071     SET_VARSIZE(res, hlen + VARHDRSZ);
00072 
00073     arg = PG_GETARG_BYTEA_P(0);
00074     len = VARSIZE(arg) - VARHDRSZ;
00075 
00076     px_md_update(md, (uint8 *) VARDATA(arg), len);
00077     px_md_finish(md, (uint8 *) VARDATA(res));
00078     px_md_free(md);
00079 
00080     PG_FREE_IF_COPY(arg, 0);
00081     PG_FREE_IF_COPY(name, 1);
00082 
00083     PG_RETURN_BYTEA_P(res);
00084 }
00085 
00086 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
00087 PG_FUNCTION_INFO_V1(pg_hmac);
00088 
00089 Datum
00090 pg_hmac(PG_FUNCTION_ARGS)
00091 {
00092     bytea      *arg;
00093     bytea      *key;
00094     text       *name;
00095     unsigned    len,
00096                 hlen,
00097                 klen;
00098     PX_HMAC    *h;
00099     bytea      *res;
00100 
00101     name = PG_GETARG_TEXT_P(2);
00102 
00103     /* will give error if fails */
00104     h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
00105 
00106     hlen = px_hmac_result_size(h);
00107 
00108     res = (text *) palloc(hlen + VARHDRSZ);
00109     SET_VARSIZE(res, hlen + VARHDRSZ);
00110 
00111     arg = PG_GETARG_BYTEA_P(0);
00112     key = PG_GETARG_BYTEA_P(1);
00113     len = VARSIZE(arg) - VARHDRSZ;
00114     klen = VARSIZE(key) - VARHDRSZ;
00115 
00116     px_hmac_init(h, (uint8 *) VARDATA(key), klen);
00117     px_hmac_update(h, (uint8 *) VARDATA(arg), len);
00118     px_hmac_finish(h, (uint8 *) VARDATA(res));
00119     px_hmac_free(h);
00120 
00121     PG_FREE_IF_COPY(arg, 0);
00122     PG_FREE_IF_COPY(key, 1);
00123     PG_FREE_IF_COPY(name, 2);
00124 
00125     PG_RETURN_BYTEA_P(res);
00126 }
00127 
00128 
00129 /* SQL function: pg_gen_salt(text) returns text */
00130 PG_FUNCTION_INFO_V1(pg_gen_salt);
00131 
00132 Datum
00133 pg_gen_salt(PG_FUNCTION_ARGS)
00134 {
00135     text       *arg0 = PG_GETARG_TEXT_PP(0);
00136     int         len;
00137     char        buf[PX_MAX_SALT_LEN + 1];
00138 
00139     text_to_cstring_buffer(arg0, buf, sizeof(buf));
00140     len = px_gen_salt(buf, buf, 0);
00141     if (len < 0)
00142         ereport(ERROR,
00143                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00144                  errmsg("gen_salt: %s", px_strerror(len))));
00145 
00146     PG_FREE_IF_COPY(arg0, 0);
00147 
00148     PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
00149 }
00150 
00151 /* SQL function: pg_gen_salt(text, int4) returns text */
00152 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
00153 
00154 Datum
00155 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
00156 {
00157     text       *arg0 = PG_GETARG_TEXT_PP(0);
00158     int         rounds = PG_GETARG_INT32(1);
00159     int         len;
00160     char        buf[PX_MAX_SALT_LEN + 1];
00161 
00162     text_to_cstring_buffer(arg0, buf, sizeof(buf));
00163     len = px_gen_salt(buf, buf, rounds);
00164     if (len < 0)
00165         ereport(ERROR,
00166                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00167                  errmsg("gen_salt: %s", px_strerror(len))));
00168 
00169     PG_FREE_IF_COPY(arg0, 0);
00170 
00171     PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
00172 }
00173 
00174 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
00175 PG_FUNCTION_INFO_V1(pg_crypt);
00176 
00177 Datum
00178 pg_crypt(PG_FUNCTION_ARGS)
00179 {
00180     text       *arg0 = PG_GETARG_TEXT_PP(0);
00181     text       *arg1 = PG_GETARG_TEXT_PP(1);
00182     char       *buf0,
00183                *buf1,
00184                *cres,
00185                *resbuf;
00186     text       *res;
00187 
00188     buf0 = text_to_cstring(arg0);
00189     buf1 = text_to_cstring(arg1);
00190 
00191     resbuf = palloc0(PX_MAX_CRYPT);
00192 
00193     cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
00194 
00195     pfree(buf0);
00196     pfree(buf1);
00197 
00198     if (cres == NULL)
00199         ereport(ERROR,
00200                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00201                  errmsg("crypt(3) returned NULL")));
00202 
00203     res = cstring_to_text(cres);
00204 
00205     pfree(resbuf);
00206 
00207     PG_FREE_IF_COPY(arg0, 0);
00208     PG_FREE_IF_COPY(arg1, 1);
00209 
00210     PG_RETURN_TEXT_P(res);
00211 }
00212 
00213 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
00214 PG_FUNCTION_INFO_V1(pg_encrypt);
00215 
00216 Datum
00217 pg_encrypt(PG_FUNCTION_ARGS)
00218 {
00219     int         err;
00220     bytea      *data,
00221                *key,
00222                *res;
00223     text       *type;
00224     PX_Combo   *c;
00225     unsigned    dlen,
00226                 klen,
00227                 rlen;
00228 
00229     type = PG_GETARG_TEXT_P(2);
00230     c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00231 
00232     data = PG_GETARG_BYTEA_P(0);
00233     key = PG_GETARG_BYTEA_P(1);
00234     dlen = VARSIZE(data) - VARHDRSZ;
00235     klen = VARSIZE(key) - VARHDRSZ;
00236 
00237     rlen = px_combo_encrypt_len(c, dlen);
00238     res = palloc(VARHDRSZ + rlen);
00239 
00240     err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
00241     if (!err)
00242         err = px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
00243                                (uint8 *) VARDATA(res), &rlen);
00244     px_combo_free(c);
00245 
00246     PG_FREE_IF_COPY(data, 0);
00247     PG_FREE_IF_COPY(key, 1);
00248     PG_FREE_IF_COPY(type, 2);
00249 
00250     if (err)
00251     {
00252         pfree(res);
00253         ereport(ERROR,
00254                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00255                  errmsg("encrypt error: %s", px_strerror(err))));
00256     }
00257 
00258     SET_VARSIZE(res, VARHDRSZ + rlen);
00259     PG_RETURN_BYTEA_P(res);
00260 }
00261 
00262 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
00263 PG_FUNCTION_INFO_V1(pg_decrypt);
00264 
00265 Datum
00266 pg_decrypt(PG_FUNCTION_ARGS)
00267 {
00268     int         err;
00269     bytea      *data,
00270                *key,
00271                *res;
00272     text       *type;
00273     PX_Combo   *c;
00274     unsigned    dlen,
00275                 klen,
00276                 rlen;
00277 
00278     type = PG_GETARG_TEXT_P(2);
00279     c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00280 
00281     data = PG_GETARG_BYTEA_P(0);
00282     key = PG_GETARG_BYTEA_P(1);
00283     dlen = VARSIZE(data) - VARHDRSZ;
00284     klen = VARSIZE(key) - VARHDRSZ;
00285 
00286     rlen = px_combo_decrypt_len(c, dlen);
00287     res = palloc(VARHDRSZ + rlen);
00288 
00289     err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
00290     if (!err)
00291         err = px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
00292                                (uint8 *) VARDATA(res), &rlen);
00293 
00294     px_combo_free(c);
00295 
00296     if (err)
00297         ereport(ERROR,
00298                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00299                  errmsg("decrypt error: %s", px_strerror(err))));
00300 
00301     SET_VARSIZE(res, VARHDRSZ + rlen);
00302 
00303     PG_FREE_IF_COPY(data, 0);
00304     PG_FREE_IF_COPY(key, 1);
00305     PG_FREE_IF_COPY(type, 2);
00306 
00307     PG_RETURN_BYTEA_P(res);
00308 }
00309 
00310 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
00311 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
00312 
00313 Datum
00314 pg_encrypt_iv(PG_FUNCTION_ARGS)
00315 {
00316     int         err;
00317     bytea      *data,
00318                *key,
00319                *iv,
00320                *res;
00321     text       *type;
00322     PX_Combo   *c;
00323     unsigned    dlen,
00324                 klen,
00325                 ivlen,
00326                 rlen;
00327 
00328     type = PG_GETARG_TEXT_P(3);
00329     c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00330 
00331     data = PG_GETARG_BYTEA_P(0);
00332     key = PG_GETARG_BYTEA_P(1);
00333     iv = PG_GETARG_BYTEA_P(2);
00334     dlen = VARSIZE(data) - VARHDRSZ;
00335     klen = VARSIZE(key) - VARHDRSZ;
00336     ivlen = VARSIZE(iv) - VARHDRSZ;
00337 
00338     rlen = px_combo_encrypt_len(c, dlen);
00339     res = palloc(VARHDRSZ + rlen);
00340 
00341     err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
00342                         (uint8 *) VARDATA(iv), ivlen);
00343     if (!err)
00344         err = px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
00345                                (uint8 *) VARDATA(res), &rlen);
00346 
00347     px_combo_free(c);
00348 
00349     if (err)
00350         ereport(ERROR,
00351                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00352                  errmsg("encrypt_iv error: %s", px_strerror(err))));
00353 
00354     SET_VARSIZE(res, VARHDRSZ + rlen);
00355 
00356     PG_FREE_IF_COPY(data, 0);
00357     PG_FREE_IF_COPY(key, 1);
00358     PG_FREE_IF_COPY(iv, 2);
00359     PG_FREE_IF_COPY(type, 3);
00360 
00361     PG_RETURN_BYTEA_P(res);
00362 }
00363 
00364 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
00365 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
00366 
00367 Datum
00368 pg_decrypt_iv(PG_FUNCTION_ARGS)
00369 {
00370     int         err;
00371     bytea      *data,
00372                *key,
00373                *iv,
00374                *res;
00375     text       *type;
00376     PX_Combo   *c;
00377     unsigned    dlen,
00378                 klen,
00379                 rlen,
00380                 ivlen;
00381 
00382     type = PG_GETARG_TEXT_P(3);
00383     c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00384 
00385     data = PG_GETARG_BYTEA_P(0);
00386     key = PG_GETARG_BYTEA_P(1);
00387     iv = PG_GETARG_BYTEA_P(2);
00388     dlen = VARSIZE(data) - VARHDRSZ;
00389     klen = VARSIZE(key) - VARHDRSZ;
00390     ivlen = VARSIZE(iv) - VARHDRSZ;
00391 
00392     rlen = px_combo_decrypt_len(c, dlen);
00393     res = palloc(VARHDRSZ + rlen);
00394 
00395     err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
00396                         (uint8 *) VARDATA(iv), ivlen);
00397     if (!err)
00398         err = px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
00399                                (uint8 *) VARDATA(res), &rlen);
00400 
00401     px_combo_free(c);
00402 
00403     if (err)
00404         ereport(ERROR,
00405                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00406                  errmsg("decrypt_iv error: %s", px_strerror(err))));
00407 
00408     SET_VARSIZE(res, VARHDRSZ + rlen);
00409 
00410     PG_FREE_IF_COPY(data, 0);
00411     PG_FREE_IF_COPY(key, 1);
00412     PG_FREE_IF_COPY(iv, 2);
00413     PG_FREE_IF_COPY(type, 3);
00414 
00415     PG_RETURN_BYTEA_P(res);
00416 }
00417 
00418 /* SQL function: pg_random_bytes(int4) returns bytea */
00419 PG_FUNCTION_INFO_V1(pg_random_bytes);
00420 
00421 Datum
00422 pg_random_bytes(PG_FUNCTION_ARGS)
00423 {
00424     int         err;
00425     int         len = PG_GETARG_INT32(0);
00426     bytea      *res;
00427 
00428     if (len < 1 || len > 1024)
00429         ereport(ERROR,
00430                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00431                  errmsg("Length not in range")));
00432 
00433     res = palloc(VARHDRSZ + len);
00434     SET_VARSIZE(res, VARHDRSZ + len);
00435 
00436     /* generate result */
00437     err = px_get_random_bytes((uint8 *) VARDATA(res), len);
00438     if (err < 0)
00439         ereport(ERROR,
00440                 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00441                  errmsg("Random generator error: %s", px_strerror(err))));
00442 
00443     PG_RETURN_BYTEA_P(res);
00444 }
00445 
00446 static void *
00447 find_provider(text *name,
00448               PFN provider_lookup,
00449               char *desc, int silent)
00450 {
00451     void       *res;
00452     char       *buf;
00453     int         err;
00454 
00455     buf = downcase_truncate_identifier(VARDATA(name),
00456                                        VARSIZE(name) - VARHDRSZ,
00457                                        false);
00458 
00459     err = provider_lookup(buf, &res);
00460 
00461     if (err && !silent)
00462         ereport(ERROR,
00463                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00464                  errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
00465 
00466     pfree(buf);
00467 
00468     return err ? NULL : res;
00469 }