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/uuid.h"
48 typedef int (*PFN
) (const char *name
, void **res
);
49 static void *find_provider(text
*name
, PFN provider_lookup
, const char *desc
,
52 /* SQL function: hash(bytea, text) returns bytea */
53 PG_FUNCTION_INFO_V1(pg_digest
);
56 pg_digest(PG_FUNCTION_ARGS
)
65 name
= PG_GETARG_TEXT_PP(1);
67 /* will give error if fails */
68 md
= find_provider(name
, (PFN
) px_find_digest
, "Digest", 0);
70 hlen
= px_md_result_size(md
);
72 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
73 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
75 arg
= PG_GETARG_BYTEA_PP(0);
76 len
= VARSIZE_ANY_EXHDR(arg
);
78 px_md_update(md
, (uint8
*) VARDATA_ANY(arg
), len
);
79 px_md_finish(md
, (uint8
*) VARDATA(res
));
82 PG_FREE_IF_COPY(arg
, 0);
83 PG_FREE_IF_COPY(name
, 1);
85 PG_RETURN_BYTEA_P(res
);
88 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
89 PG_FUNCTION_INFO_V1(pg_hmac
);
92 pg_hmac(PG_FUNCTION_ARGS
)
103 name
= PG_GETARG_TEXT_PP(2);
105 /* will give error if fails */
106 h
= find_provider(name
, (PFN
) px_find_hmac
, "HMAC", 0);
108 hlen
= px_hmac_result_size(h
);
110 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
111 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
113 arg
= PG_GETARG_BYTEA_PP(0);
114 key
= PG_GETARG_BYTEA_PP(1);
115 len
= VARSIZE_ANY_EXHDR(arg
);
116 klen
= VARSIZE_ANY_EXHDR(key
);
118 px_hmac_init(h
, (uint8
*) VARDATA_ANY(key
), klen
);
119 px_hmac_update(h
, (uint8
*) VARDATA_ANY(arg
), len
);
120 px_hmac_finish(h
, (uint8
*) VARDATA(res
));
123 PG_FREE_IF_COPY(arg
, 0);
124 PG_FREE_IF_COPY(key
, 1);
125 PG_FREE_IF_COPY(name
, 2);
127 PG_RETURN_BYTEA_P(res
);
131 /* SQL function: pg_gen_salt(text) returns text */
132 PG_FUNCTION_INFO_V1(pg_gen_salt
);
135 pg_gen_salt(PG_FUNCTION_ARGS
)
137 text
*arg0
= PG_GETARG_TEXT_PP(0);
139 char buf
[PX_MAX_SALT_LEN
+ 1];
141 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
142 len
= px_gen_salt(buf
, buf
, 0);
145 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
146 errmsg("gen_salt: %s", px_strerror(len
))));
148 PG_FREE_IF_COPY(arg0
, 0);
150 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
153 /* SQL function: pg_gen_salt(text, int4) returns text */
154 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds
);
157 pg_gen_salt_rounds(PG_FUNCTION_ARGS
)
159 text
*arg0
= PG_GETARG_TEXT_PP(0);
160 int rounds
= PG_GETARG_INT32(1);
162 char buf
[PX_MAX_SALT_LEN
+ 1];
164 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
165 len
= px_gen_salt(buf
, buf
, rounds
);
168 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
169 errmsg("gen_salt: %s", px_strerror(len
))));
171 PG_FREE_IF_COPY(arg0
, 0);
173 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
176 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
177 PG_FUNCTION_INFO_V1(pg_crypt
);
180 pg_crypt(PG_FUNCTION_ARGS
)
182 text
*arg0
= PG_GETARG_TEXT_PP(0);
183 text
*arg1
= PG_GETARG_TEXT_PP(1);
190 buf0
= text_to_cstring(arg0
);
191 buf1
= text_to_cstring(arg1
);
193 resbuf
= palloc0(PX_MAX_CRYPT
);
195 cres
= px_crypt(buf0
, buf1
, resbuf
, PX_MAX_CRYPT
);
202 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
203 errmsg("crypt(3) returned NULL")));
205 res
= cstring_to_text(cres
);
209 PG_FREE_IF_COPY(arg0
, 0);
210 PG_FREE_IF_COPY(arg1
, 1);
212 PG_RETURN_TEXT_P(res
);
215 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
216 PG_FUNCTION_INFO_V1(pg_encrypt
);
219 pg_encrypt(PG_FUNCTION_ARGS
)
231 type
= PG_GETARG_TEXT_PP(2);
232 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
234 data
= PG_GETARG_BYTEA_PP(0);
235 key
= PG_GETARG_BYTEA_PP(1);
236 dlen
= VARSIZE_ANY_EXHDR(data
);
237 klen
= VARSIZE_ANY_EXHDR(key
);
239 rlen
= px_combo_encrypt_len(c
, dlen
);
240 res
= palloc(VARHDRSZ
+ rlen
);
242 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
, NULL
, 0);
244 err
= px_combo_encrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
245 (uint8
*) VARDATA(res
), &rlen
);
248 PG_FREE_IF_COPY(data
, 0);
249 PG_FREE_IF_COPY(key
, 1);
250 PG_FREE_IF_COPY(type
, 2);
256 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
257 errmsg("encrypt error: %s", px_strerror(err
))));
260 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
261 PG_RETURN_BYTEA_P(res
);
264 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
265 PG_FUNCTION_INFO_V1(pg_decrypt
);
268 pg_decrypt(PG_FUNCTION_ARGS
)
280 type
= PG_GETARG_TEXT_PP(2);
281 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
283 data
= PG_GETARG_BYTEA_PP(0);
284 key
= PG_GETARG_BYTEA_PP(1);
285 dlen
= VARSIZE_ANY_EXHDR(data
);
286 klen
= VARSIZE_ANY_EXHDR(key
);
288 rlen
= px_combo_decrypt_len(c
, dlen
);
289 res
= palloc(VARHDRSZ
+ rlen
);
291 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
, NULL
, 0);
293 err
= px_combo_decrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
294 (uint8
*) VARDATA(res
), &rlen
);
300 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
301 errmsg("decrypt error: %s", px_strerror(err
))));
303 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
305 PG_FREE_IF_COPY(data
, 0);
306 PG_FREE_IF_COPY(key
, 1);
307 PG_FREE_IF_COPY(type
, 2);
309 PG_RETURN_BYTEA_P(res
);
312 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
313 PG_FUNCTION_INFO_V1(pg_encrypt_iv
);
316 pg_encrypt_iv(PG_FUNCTION_ARGS
)
330 type
= PG_GETARG_TEXT_PP(3);
331 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
333 data
= PG_GETARG_BYTEA_PP(0);
334 key
= PG_GETARG_BYTEA_PP(1);
335 iv
= PG_GETARG_BYTEA_PP(2);
336 dlen
= VARSIZE_ANY_EXHDR(data
);
337 klen
= VARSIZE_ANY_EXHDR(key
);
338 ivlen
= VARSIZE_ANY_EXHDR(iv
);
340 rlen
= px_combo_encrypt_len(c
, dlen
);
341 res
= palloc(VARHDRSZ
+ rlen
);
343 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
,
344 (uint8
*) VARDATA_ANY(iv
), ivlen
);
346 err
= px_combo_encrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
347 (uint8
*) VARDATA(res
), &rlen
);
353 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
354 errmsg("encrypt_iv error: %s", px_strerror(err
))));
356 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
358 PG_FREE_IF_COPY(data
, 0);
359 PG_FREE_IF_COPY(key
, 1);
360 PG_FREE_IF_COPY(iv
, 2);
361 PG_FREE_IF_COPY(type
, 3);
363 PG_RETURN_BYTEA_P(res
);
366 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
367 PG_FUNCTION_INFO_V1(pg_decrypt_iv
);
370 pg_decrypt_iv(PG_FUNCTION_ARGS
)
384 type
= PG_GETARG_TEXT_PP(3);
385 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
387 data
= PG_GETARG_BYTEA_PP(0);
388 key
= PG_GETARG_BYTEA_PP(1);
389 iv
= PG_GETARG_BYTEA_PP(2);
390 dlen
= VARSIZE_ANY_EXHDR(data
);
391 klen
= VARSIZE_ANY_EXHDR(key
);
392 ivlen
= VARSIZE_ANY_EXHDR(iv
);
394 rlen
= px_combo_decrypt_len(c
, dlen
);
395 res
= palloc(VARHDRSZ
+ rlen
);
397 err
= px_combo_init(c
, (uint8
*) VARDATA_ANY(key
), klen
,
398 (uint8
*) VARDATA_ANY(iv
), ivlen
);
400 err
= px_combo_decrypt(c
, (uint8
*) VARDATA_ANY(data
), dlen
,
401 (uint8
*) VARDATA(res
), &rlen
);
407 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
408 errmsg("decrypt_iv error: %s", px_strerror(err
))));
410 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
412 PG_FREE_IF_COPY(data
, 0);
413 PG_FREE_IF_COPY(key
, 1);
414 PG_FREE_IF_COPY(iv
, 2);
415 PG_FREE_IF_COPY(type
, 3);
417 PG_RETURN_BYTEA_P(res
);
420 /* SQL function: pg_random_bytes(int4) returns bytea */
421 PG_FUNCTION_INFO_V1(pg_random_bytes
);
424 pg_random_bytes(PG_FUNCTION_ARGS
)
426 int len
= PG_GETARG_INT32(0);
429 if (len
< 1 || len
> 1024)
431 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
432 errmsg("Length not in range")));
434 res
= palloc(VARHDRSZ
+ len
);
435 SET_VARSIZE(res
, VARHDRSZ
+ len
);
437 /* generate result */
438 if (!pg_strong_random(VARDATA(res
), len
))
439 px_THROW_ERROR(PXE_NO_RANDOM
);
441 PG_RETURN_BYTEA_P(res
);
444 /* SQL function: gen_random_uuid() returns uuid */
445 PG_FUNCTION_INFO_V1(pg_random_uuid
);
448 pg_random_uuid(PG_FUNCTION_ARGS
)
450 /* redirect to built-in function */
451 return gen_random_uuid(fcinfo
);
455 find_provider(text
*name
,
457 const char *desc
, int silent
)
463 buf
= downcase_truncate_identifier(VARDATA_ANY(name
),
464 VARSIZE_ANY_EXHDR(name
),
467 err
= provider_lookup(buf
, &res
);
471 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
472 errmsg("Cannot use \"%s\": %s", buf
, px_strerror(err
))));
476 return err
? NULL
: res
;