3 * Various cryptographic stuff for PostgreSQL.
5 * Copyright (c) 2001 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * contrib/pgcrypto/pgcrypto.c
36 #include "parser/scansup.h"
40 #include "utils/builtins.h"
41 #include "utils/guc.h"
48 static const struct config_enum_entry builtin_crypto_options
[] = {
50 {"off", BC_OFF
, false},
51 {"fips", BC_FIPS
, false},
55 typedef int (*PFN
) (const char *name
, void **res
);
56 static void *find_provider(text
*name
, PFN provider_lookup
, const char *desc
,
59 int builtin_crypto_enabled
= BC_ON
;
62 * Entrypoint of this module.
67 DefineCustomEnumVariable("pgcrypto.builtin_crypto_enabled",
68 "Sets if builtin crypto functions are enabled.",
69 "\"on\" enables builtin crypto, \"off\" unconditionally disables and \"fips\" "
70 "will disable builtin crypto if OpenSSL is in FIPS mode",
71 &builtin_crypto_enabled
,
73 builtin_crypto_options
,
79 MarkGUCPrefixReserved("pgcrypto");
82 /* SQL function: hash(bytea, text) returns bytea */
83 PG_FUNCTION_INFO_V1(pg_digest
);
86 pg_digest(PG_FUNCTION_ARGS
)
95 name
= PG_GETARG_TEXT_PP(1);
97 /* will give error if fails */
98 md
= find_provider(name
, (PFN
) px_find_digest
, "Digest", 0);
100 hlen
= px_md_result_size(md
);
102 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
103 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
105 arg
= PG_GETARG_BYTEA_PP(0);
106 len
= VARSIZE_ANY_EXHDR(arg
);
108 px_md_update(md
, (uint8
*) VARDATA_ANY(arg
), len
);
109 px_md_finish(md
, (uint8
*) VARDATA(res
));
112 PG_FREE_IF_COPY(arg
, 0);
113 PG_FREE_IF_COPY(name
, 1);
115 PG_RETURN_BYTEA_P(res
);
118 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
119 PG_FUNCTION_INFO_V1(pg_hmac
);
122 pg_hmac(PG_FUNCTION_ARGS
)
133 name
= PG_GETARG_TEXT_PP(2);
135 /* will give error if fails */
136 h
= find_provider(name
, (PFN
) px_find_hmac
, "HMAC", 0);
138 hlen
= px_hmac_result_size(h
);
140 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
141 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
143 arg
= PG_GETARG_BYTEA_PP(0);
144 key
= PG_GETARG_BYTEA_PP(1);
145 len
= VARSIZE_ANY_EXHDR(arg
);
146 klen
= VARSIZE_ANY_EXHDR(key
);
148 px_hmac_init(h
, (uint8
*) VARDATA_ANY(key
), klen
);
149 px_hmac_update(h
, (uint8
*) VARDATA_ANY(arg
), len
);
150 px_hmac_finish(h
, (uint8
*) VARDATA(res
));
153 PG_FREE_IF_COPY(arg
, 0);
154 PG_FREE_IF_COPY(key
, 1);
155 PG_FREE_IF_COPY(name
, 2);
157 PG_RETURN_BYTEA_P(res
);
161 /* SQL function: pg_gen_salt(text) returns text */
162 PG_FUNCTION_INFO_V1(pg_gen_salt
);
165 pg_gen_salt(PG_FUNCTION_ARGS
)
167 text
*arg0
= PG_GETARG_TEXT_PP(0);
169 char buf
[PX_MAX_SALT_LEN
+ 1];
171 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
172 len
= px_gen_salt(buf
, buf
, 0);
175 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
176 errmsg("gen_salt: %s", px_strerror(len
))));
178 PG_FREE_IF_COPY(arg0
, 0);
180 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
183 /* SQL function: pg_gen_salt(text, int4) returns text */
184 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds
);
187 pg_gen_salt_rounds(PG_FUNCTION_ARGS
)
189 text
*arg0
= PG_GETARG_TEXT_PP(0);
190 int rounds
= PG_GETARG_INT32(1);
192 char buf
[PX_MAX_SALT_LEN
+ 1];
194 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
195 len
= px_gen_salt(buf
, buf
, rounds
);
198 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
199 errmsg("gen_salt: %s", px_strerror(len
))));
201 PG_FREE_IF_COPY(arg0
, 0);
203 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
206 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
207 PG_FUNCTION_INFO_V1(pg_crypt
);
210 pg_crypt(PG_FUNCTION_ARGS
)
212 text
*arg0
= PG_GETARG_TEXT_PP(0);
213 text
*arg1
= PG_GETARG_TEXT_PP(1);
220 buf0
= text_to_cstring(arg0
);
221 buf1
= text_to_cstring(arg1
);
223 resbuf
= palloc0(PX_MAX_CRYPT
);
225 cres
= px_crypt(buf0
, buf1
, resbuf
, PX_MAX_CRYPT
);
232 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
233 errmsg("crypt(3) returned NULL")));
235 res
= cstring_to_text(cres
);
239 PG_FREE_IF_COPY(arg0
, 0);
240 PG_FREE_IF_COPY(arg1
, 1);
242 PG_RETURN_TEXT_P(res
);
245 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
246 PG_FUNCTION_INFO_V1(pg_encrypt
);
249 pg_encrypt(PG_FUNCTION_ARGS
)
261 type
= PG_GETARG_TEXT_PP(2);
262 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
264 data
= PG_GETARG_BYTEA_PP(0);
265 key
= PG_GETARG_BYTEA_PP(1);
266 dlen
= VARSIZE_ANY_EXHDR(data
);
267 klen
= VARSIZE_ANY_EXHDR(key
);
269 rlen
= px_combo_encrypt_len(c
, dlen
);
270 res
= palloc(VARHDRSZ
+ rlen
);
272 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
, NULL
, 0);
274 err
= px_combo_encrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
275 (uint8
*) VARDATA(res
), &rlen
);
278 PG_FREE_IF_COPY(data
, 0);
279 PG_FREE_IF_COPY(key
, 1);
280 PG_FREE_IF_COPY(type
, 2);
286 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
287 errmsg("encrypt error: %s", px_strerror(err
))));
290 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
291 PG_RETURN_BYTEA_P(res
);
294 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
295 PG_FUNCTION_INFO_V1(pg_decrypt
);
298 pg_decrypt(PG_FUNCTION_ARGS
)
310 type
= PG_GETARG_TEXT_PP(2);
311 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
313 data
= PG_GETARG_BYTEA_PP(0);
314 key
= PG_GETARG_BYTEA_PP(1);
315 dlen
= VARSIZE_ANY_EXHDR(data
);
316 klen
= VARSIZE_ANY_EXHDR(key
);
318 rlen
= px_combo_decrypt_len(c
, dlen
);
319 res
= palloc(VARHDRSZ
+ rlen
);
321 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
, NULL
, 0);
323 err
= px_combo_decrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
324 (uint8
*) VARDATA(res
), &rlen
);
330 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
331 errmsg("decrypt error: %s", px_strerror(err
))));
333 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
335 PG_FREE_IF_COPY(data
, 0);
336 PG_FREE_IF_COPY(key
, 1);
337 PG_FREE_IF_COPY(type
, 2);
339 PG_RETURN_BYTEA_P(res
);
342 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
343 PG_FUNCTION_INFO_V1(pg_encrypt_iv
);
346 pg_encrypt_iv(PG_FUNCTION_ARGS
)
360 type
= PG_GETARG_TEXT_PP(3);
361 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
363 data
= PG_GETARG_BYTEA_PP(0);
364 key
= PG_GETARG_BYTEA_PP(1);
365 iv
= PG_GETARG_BYTEA_PP(2);
366 dlen
= VARSIZE_ANY_EXHDR(data
);
367 klen
= VARSIZE_ANY_EXHDR(key
);
368 ivlen
= VARSIZE_ANY_EXHDR(iv
);
370 rlen
= px_combo_encrypt_len(c
, dlen
);
371 res
= palloc(VARHDRSZ
+ rlen
);
373 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
,
374 (uint8
*) VARDATA_ANY(iv
), ivlen
);
376 err
= px_combo_encrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
377 (uint8
*) VARDATA(res
), &rlen
);
383 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
384 errmsg("encrypt_iv error: %s", px_strerror(err
))));
386 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
388 PG_FREE_IF_COPY(data
, 0);
389 PG_FREE_IF_COPY(key
, 1);
390 PG_FREE_IF_COPY(iv
, 2);
391 PG_FREE_IF_COPY(type
, 3);
393 PG_RETURN_BYTEA_P(res
);
396 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
397 PG_FUNCTION_INFO_V1(pg_decrypt_iv
);
400 pg_decrypt_iv(PG_FUNCTION_ARGS
)
414 type
= PG_GETARG_TEXT_PP(3);
415 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
417 data
= PG_GETARG_BYTEA_PP(0);
418 key
= PG_GETARG_BYTEA_PP(1);
419 iv
= PG_GETARG_BYTEA_PP(2);
420 dlen
= VARSIZE_ANY_EXHDR(data
);
421 klen
= VARSIZE_ANY_EXHDR(key
);
422 ivlen
= VARSIZE_ANY_EXHDR(iv
);
424 rlen
= px_combo_decrypt_len(c
, dlen
);
425 res
= palloc(VARHDRSZ
+ rlen
);
427 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
,
428 (uint8
*) VARDATA_ANY(iv
), ivlen
);
430 err
= px_combo_decrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
431 (uint8
*) VARDATA(res
), &rlen
);
437 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
438 errmsg("decrypt_iv error: %s", px_strerror(err
))));
440 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
442 PG_FREE_IF_COPY(data
, 0);
443 PG_FREE_IF_COPY(key
, 1);
444 PG_FREE_IF_COPY(iv
, 2);
445 PG_FREE_IF_COPY(type
, 3);
447 PG_RETURN_BYTEA_P(res
);
450 /* SQL function: pg_random_bytes(int4) returns bytea */
451 PG_FUNCTION_INFO_V1(pg_random_bytes
);
454 pg_random_bytes(PG_FUNCTION_ARGS
)
456 int len
= PG_GETARG_INT32(0);
459 if (len
< 1 || len
> 1024)
461 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
462 errmsg("Length not in range")));
464 res
= palloc(VARHDRSZ
+ len
);
465 SET_VARSIZE(res
, VARHDRSZ
+ len
);
467 /* generate result */
468 if (!pg_strong_random(VARDATA(res
), len
))
469 px_THROW_ERROR(PXE_NO_RANDOM
);
471 PG_RETURN_BYTEA_P(res
);
474 /* SQL function: gen_random_uuid() returns uuid */
475 PG_FUNCTION_INFO_V1(pg_random_uuid
);
478 pg_random_uuid(PG_FUNCTION_ARGS
)
480 /* redirect to built-in function */
481 return gen_random_uuid(fcinfo
);
484 PG_FUNCTION_INFO_V1(pg_check_fipsmode
);
487 pg_check_fipsmode(PG_FUNCTION_ARGS
)
489 PG_RETURN_BOOL(CheckFIPSMode());
493 find_provider(text
*name
,
495 const char *desc
, int silent
)
501 buf
= downcase_truncate_identifier(VARDATA_ANY(name
),
502 VARSIZE_ANY_EXHDR(name
),
505 err
= provider_lookup(buf
, &res
);
509 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
510 errmsg("Cannot use \"%s\": %s", buf
, px_strerror(err
))));
514 return err
? NULL
: res
;