LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgcrypto.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 166 183 90.7 %
Date: 2020-06-01 08:06:25 Functions: 22 24 91.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13