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

Generated by: LCOV version 2.0-1