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;