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

Generated by: LCOV version 1.14