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
37 #include "parser/scansup.h"
38 #include "utils/builtins.h"
48 typedef int (*PFN
) (const char *name
, void **res
);
49 static void *find_provider(text
*name
, PFN pf
, char *desc
, int silent
);
51 /* SQL function: hash(bytea, text) returns bytea */
52 PG_FUNCTION_INFO_V1(pg_digest
);
55 pg_digest(PG_FUNCTION_ARGS
)
64 name
= PG_GETARG_TEXT_P(1);
66 /* will give error if fails */
67 md
= find_provider(name
, (PFN
) px_find_digest
, "Digest", 0);
69 hlen
= px_md_result_size(md
);
71 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
72 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
74 arg
= PG_GETARG_BYTEA_P(0);
75 len
= VARSIZE(arg
) - VARHDRSZ
;
77 px_md_update(md
, (uint8
*) VARDATA(arg
), len
);
78 px_md_finish(md
, (uint8
*) VARDATA(res
));
81 PG_FREE_IF_COPY(arg
, 0);
82 PG_FREE_IF_COPY(name
, 1);
84 PG_RETURN_BYTEA_P(res
);
87 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
88 PG_FUNCTION_INFO_V1(pg_hmac
);
91 pg_hmac(PG_FUNCTION_ARGS
)
102 name
= PG_GETARG_TEXT_P(2);
104 /* will give error if fails */
105 h
= find_provider(name
, (PFN
) px_find_hmac
, "HMAC", 0);
107 hlen
= px_hmac_result_size(h
);
109 res
= (text
*) palloc(hlen
+ VARHDRSZ
);
110 SET_VARSIZE(res
, hlen
+ VARHDRSZ
);
112 arg
= PG_GETARG_BYTEA_P(0);
113 key
= PG_GETARG_BYTEA_P(1);
114 len
= VARSIZE(arg
) - VARHDRSZ
;
115 klen
= VARSIZE(key
) - VARHDRSZ
;
117 px_hmac_init(h
, (uint8
*) VARDATA(key
), klen
);
118 px_hmac_update(h
, (uint8
*) VARDATA(arg
), len
);
119 px_hmac_finish(h
, (uint8
*) VARDATA(res
));
122 PG_FREE_IF_COPY(arg
, 0);
123 PG_FREE_IF_COPY(key
, 1);
124 PG_FREE_IF_COPY(name
, 2);
126 PG_RETURN_BYTEA_P(res
);
130 /* SQL function: pg_gen_salt(text) returns text */
131 PG_FUNCTION_INFO_V1(pg_gen_salt
);
134 pg_gen_salt(PG_FUNCTION_ARGS
)
136 text
*arg0
= PG_GETARG_TEXT_PP(0);
138 char buf
[PX_MAX_SALT_LEN
+ 1];
140 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
141 len
= px_gen_salt(buf
, buf
, 0);
144 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
145 errmsg("gen_salt: %s", px_strerror(len
))));
147 PG_FREE_IF_COPY(arg0
, 0);
149 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
152 /* SQL function: pg_gen_salt(text, int4) returns text */
153 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds
);
156 pg_gen_salt_rounds(PG_FUNCTION_ARGS
)
158 text
*arg0
= PG_GETARG_TEXT_PP(0);
159 int rounds
= PG_GETARG_INT32(1);
161 char buf
[PX_MAX_SALT_LEN
+ 1];
163 text_to_cstring_buffer(arg0
, buf
, sizeof(buf
));
164 len
= px_gen_salt(buf
, buf
, rounds
);
167 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
168 errmsg("gen_salt: %s", px_strerror(len
))));
170 PG_FREE_IF_COPY(arg0
, 0);
172 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf
, len
));
175 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
176 PG_FUNCTION_INFO_V1(pg_crypt
);
179 pg_crypt(PG_FUNCTION_ARGS
)
181 text
*arg0
= PG_GETARG_TEXT_PP(0);
182 text
*arg1
= PG_GETARG_TEXT_PP(1);
189 buf0
= text_to_cstring(arg0
);
190 buf1
= text_to_cstring(arg1
);
192 resbuf
= palloc0(PX_MAX_CRYPT
);
194 cres
= px_crypt(buf0
, buf1
, resbuf
, PX_MAX_CRYPT
);
201 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
202 errmsg("crypt(3) returned NULL")));
204 res
= cstring_to_text(cres
);
208 PG_FREE_IF_COPY(arg0
, 0);
209 PG_FREE_IF_COPY(arg1
, 1);
211 PG_RETURN_TEXT_P(res
);
214 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
215 PG_FUNCTION_INFO_V1(pg_encrypt
);
218 pg_encrypt(PG_FUNCTION_ARGS
)
230 type
= PG_GETARG_TEXT_P(2);
231 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
233 data
= PG_GETARG_BYTEA_P(0);
234 key
= PG_GETARG_BYTEA_P(1);
235 dlen
= VARSIZE(data
) - VARHDRSZ
;
236 klen
= VARSIZE(key
) - VARHDRSZ
;
238 rlen
= px_combo_encrypt_len(c
, dlen
);
239 res
= palloc(VARHDRSZ
+ rlen
);
241 err
= px_combo_init(c
, (uint8
*) VARDATA(key
), klen
, NULL
, 0);
243 err
= px_combo_encrypt(c
, (uint8
*) VARDATA(data
), dlen
,
244 (uint8
*) VARDATA(res
), &rlen
);
247 PG_FREE_IF_COPY(data
, 0);
248 PG_FREE_IF_COPY(key
, 1);
249 PG_FREE_IF_COPY(type
, 2);
255 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
256 errmsg("encrypt error: %s", px_strerror(err
))));
259 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
260 PG_RETURN_BYTEA_P(res
);
263 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
264 PG_FUNCTION_INFO_V1(pg_decrypt
);
267 pg_decrypt(PG_FUNCTION_ARGS
)
279 type
= PG_GETARG_TEXT_P(2);
280 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
282 data
= PG_GETARG_BYTEA_P(0);
283 key
= PG_GETARG_BYTEA_P(1);
284 dlen
= VARSIZE(data
) - VARHDRSZ
;
285 klen
= VARSIZE(key
) - VARHDRSZ
;
287 rlen
= px_combo_decrypt_len(c
, dlen
);
288 res
= palloc(VARHDRSZ
+ rlen
);
290 err
= px_combo_init(c
, (uint8
*) VARDATA(key
), klen
, NULL
, 0);
292 err
= px_combo_decrypt(c
, (uint8
*) VARDATA(data
), dlen
,
293 (uint8
*) VARDATA(res
), &rlen
);
299 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
300 errmsg("decrypt error: %s", px_strerror(err
))));
302 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
304 PG_FREE_IF_COPY(data
, 0);
305 PG_FREE_IF_COPY(key
, 1);
306 PG_FREE_IF_COPY(type
, 2);
308 PG_RETURN_BYTEA_P(res
);
311 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
312 PG_FUNCTION_INFO_V1(pg_encrypt_iv
);
315 pg_encrypt_iv(PG_FUNCTION_ARGS
)
329 type
= PG_GETARG_TEXT_P(3);
330 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
332 data
= PG_GETARG_BYTEA_P(0);
333 key
= PG_GETARG_BYTEA_P(1);
334 iv
= PG_GETARG_BYTEA_P(2);
335 dlen
= VARSIZE(data
) - VARHDRSZ
;
336 klen
= VARSIZE(key
) - VARHDRSZ
;
337 ivlen
= VARSIZE(iv
) - VARHDRSZ
;
339 rlen
= px_combo_encrypt_len(c
, dlen
);
340 res
= palloc(VARHDRSZ
+ rlen
);
342 err
= px_combo_init(c
, (uint8
*) VARDATA(key
), klen
,
343 (uint8
*) VARDATA(iv
), ivlen
);
345 px_combo_encrypt(c
, (uint8
*) VARDATA(data
), dlen
,
346 (uint8
*) VARDATA(res
), &rlen
);
352 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
353 errmsg("encrypt_iv error: %s", px_strerror(err
))));
355 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
357 PG_FREE_IF_COPY(data
, 0);
358 PG_FREE_IF_COPY(key
, 1);
359 PG_FREE_IF_COPY(iv
, 2);
360 PG_FREE_IF_COPY(type
, 3);
362 PG_RETURN_BYTEA_P(res
);
365 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
366 PG_FUNCTION_INFO_V1(pg_decrypt_iv
);
369 pg_decrypt_iv(PG_FUNCTION_ARGS
)
383 type
= PG_GETARG_TEXT_P(3);
384 c
= find_provider(type
, (PFN
) px_find_combo
, "Cipher", 0);
386 data
= PG_GETARG_BYTEA_P(0);
387 key
= PG_GETARG_BYTEA_P(1);
388 iv
= PG_GETARG_BYTEA_P(2);
389 dlen
= VARSIZE(data
) - VARHDRSZ
;
390 klen
= VARSIZE(key
) - VARHDRSZ
;
391 ivlen
= VARSIZE(iv
) - VARHDRSZ
;
393 rlen
= px_combo_decrypt_len(c
, dlen
);
394 res
= palloc(VARHDRSZ
+ rlen
);
396 err
= px_combo_init(c
, (uint8
*) VARDATA(key
), klen
,
397 (uint8
*) VARDATA(iv
), ivlen
);
399 px_combo_decrypt(c
, (uint8
*) VARDATA(data
), dlen
,
400 (uint8
*) VARDATA(res
), &rlen
);
406 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
407 errmsg("decrypt_iv error: %s", px_strerror(err
))));
409 SET_VARSIZE(res
, VARHDRSZ
+ rlen
);
411 PG_FREE_IF_COPY(data
, 0);
412 PG_FREE_IF_COPY(key
, 1);
413 PG_FREE_IF_COPY(iv
, 2);
414 PG_FREE_IF_COPY(type
, 3);
416 PG_RETURN_BYTEA_P(res
);
419 /* SQL function: pg_random_bytes(int4) returns bytea */
420 PG_FUNCTION_INFO_V1(pg_random_bytes
);
423 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 err
= px_get_random_bytes((uint8
*) VARDATA(res
), len
);
441 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION
),
442 errmsg("Random generator error: %s", px_strerror(err
))));
444 PG_RETURN_BYTEA_P(res
);
448 find_provider(text
*name
,
450 char *desc
, int silent
)
456 buf
= downcase_truncate_identifier(VARDATA(name
),
457 VARSIZE(name
) - VARHDRSZ
,
460 err
= provider_lookup(buf
, &res
);
464 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
465 errmsg("Cannot use \"%s\": %s", buf
, px_strerror(err
))));
469 return err
? NULL
: res
;