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

Generated by: LCOV version 1.14