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
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.16 2004-05-07 00:24:57 tgl Exp $
37
#include "parser/scansup.h"
45
typedef int (*PFN) (const char *name, void **res);
47
find_provider(text *name, PFN pf, char *desc, int silent);
49
/* SQL function: hash(text, text) returns text */
50
PG_FUNCTION_INFO_V1(pg_digest);
53
pg_digest(PG_FUNCTION_ARGS)
62
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
65
name = PG_GETARG_TEXT_P(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
VARATT_SIZEP(res) = hlen + VARHDRSZ;
75
arg = PG_GETARG_BYTEA_P(0);
76
len = VARSIZE(arg) - VARHDRSZ;
78
px_md_update(md, VARDATA(arg), len);
79
px_md_finish(md, VARDATA(res));
82
PG_FREE_IF_COPY(arg, 0);
83
PG_FREE_IF_COPY(name, 1);
85
PG_RETURN_BYTEA_P(res);
88
/* check if given hash exists */
89
PG_FUNCTION_INFO_V1(pg_digest_exists);
92
pg_digest_exists(PG_FUNCTION_ARGS)
100
name = PG_GETARG_TEXT_P(0);
102
res = find_provider(name, (PFN) px_find_digest, "Digest", 1);
104
PG_FREE_IF_COPY(name, 0);
107
PG_RETURN_BOOL(false);
111
PG_RETURN_BOOL(true);
114
/* SQL function: hmac(data:text, key:text, type:text) */
115
PG_FUNCTION_INFO_V1(pg_hmac);
118
pg_hmac(PG_FUNCTION_ARGS)
129
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
132
name = PG_GETARG_TEXT_P(2);
134
/* will give error if fails */
135
h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
137
hlen = px_hmac_result_size(h);
139
res = (text *) palloc(hlen + VARHDRSZ);
140
VARATT_SIZEP(res) = hlen + VARHDRSZ;
142
arg = PG_GETARG_BYTEA_P(0);
143
key = PG_GETARG_BYTEA_P(1);
144
len = VARSIZE(arg) - VARHDRSZ;
145
klen = VARSIZE(key) - VARHDRSZ;
147
px_hmac_init(h, VARDATA(key), klen);
148
px_hmac_update(h, VARDATA(arg), len);
149
px_hmac_finish(h, VARDATA(res));
152
PG_FREE_IF_COPY(arg, 0);
153
PG_FREE_IF_COPY(key, 1);
154
PG_FREE_IF_COPY(name, 2);
156
PG_RETURN_BYTEA_P(res);
159
/* check if given hmac type exists */
160
PG_FUNCTION_INFO_V1(pg_hmac_exists);
163
pg_hmac_exists(PG_FUNCTION_ARGS)
171
name = PG_GETARG_TEXT_P(0);
173
h = find_provider(name, (PFN) px_find_hmac, "HMAC", 1);
175
PG_FREE_IF_COPY(name, 0);
180
PG_RETURN_BOOL(true);
182
PG_RETURN_BOOL(false);
186
/* SQL function: pg_gen_salt(text) returns text */
187
PG_FUNCTION_INFO_V1(pg_gen_salt);
190
pg_gen_salt(PG_FUNCTION_ARGS)
195
char buf[PX_MAX_SALT_LEN + 1];
200
arg0 = PG_GETARG_TEXT_P(0);
202
len = VARSIZE(arg0) - VARHDRSZ;
203
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
204
memcpy(buf, VARDATA(arg0), len);
206
len = px_gen_salt(buf, buf, 0);
209
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
210
errmsg("no such crypt algorithm")));
212
res = (text *) palloc(len + VARHDRSZ);
213
VARATT_SIZEP(res) = len + VARHDRSZ;
214
memcpy(VARDATA(res), buf, len);
216
PG_FREE_IF_COPY(arg0, 0);
218
PG_RETURN_TEXT_P(res);
221
/* SQL function: pg_gen_salt(text, int4) returns text */
222
PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
225
pg_gen_salt_rounds(PG_FUNCTION_ARGS)
231
char buf[PX_MAX_SALT_LEN + 1];
233
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
236
arg0 = PG_GETARG_TEXT_P(0);
237
rounds = PG_GETARG_INT32(1);
239
len = VARSIZE(arg0) - VARHDRSZ;
240
len = len > PX_MAX_SALT_LEN ? PX_MAX_SALT_LEN : len;
241
memcpy(buf, VARDATA(arg0), len);
243
len = px_gen_salt(buf, buf, rounds);
246
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
247
errmsg("no such crypt algorithm or bad number of rounds")));
249
res = (text *) palloc(len + VARHDRSZ);
250
VARATT_SIZEP(res) = len + VARHDRSZ;
251
memcpy(VARDATA(res), buf, len);
253
PG_FREE_IF_COPY(arg0, 0);
255
PG_RETURN_TEXT_P(res);
258
/* SQL function: pg_crypt(psw:text, salt:text) returns text */
259
PG_FUNCTION_INFO_V1(pg_crypt);
262
pg_crypt(PG_FUNCTION_ARGS)
275
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
278
arg0 = PG_GETARG_TEXT_P(0);
279
arg1 = PG_GETARG_TEXT_P(1);
280
len0 = VARSIZE(arg0) - VARHDRSZ;
281
len1 = VARSIZE(arg1) - VARHDRSZ;
283
buf0 = palloc(len0 + 1);
284
buf1 = palloc(len1 + 1);
286
memcpy(buf0, VARDATA(arg0), len0);
287
memcpy(buf1, VARDATA(arg1), len1);
292
resbuf = palloc(PX_MAX_CRYPT);
294
memset(resbuf, 0, PX_MAX_CRYPT);
296
cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
303
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
304
errmsg("crypt(3) returned NULL")));
308
res = (text *) palloc(clen + VARHDRSZ);
309
VARATT_SIZEP(res) = clen + VARHDRSZ;
310
memcpy(VARDATA(res), cres, clen);
313
PG_FREE_IF_COPY(arg0, 0);
314
PG_FREE_IF_COPY(arg1, 1);
316
PG_RETURN_TEXT_P(res);
319
/* SQL function: pg_encrypt(text, text, text) returns text */
320
PG_FUNCTION_INFO_V1(pg_encrypt);
323
pg_encrypt(PG_FUNCTION_ARGS)
335
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
338
type = PG_GETARG_TEXT_P(2);
339
c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
341
data = PG_GETARG_BYTEA_P(0);
342
key = PG_GETARG_BYTEA_P(1);
343
dlen = VARSIZE(data) - VARHDRSZ;
344
klen = VARSIZE(key) - VARHDRSZ;
346
rlen = px_combo_encrypt_len(c, dlen);
347
res = palloc(VARHDRSZ + rlen);
349
err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
351
err = px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
354
PG_FREE_IF_COPY(data, 0);
355
PG_FREE_IF_COPY(key, 1);
356
PG_FREE_IF_COPY(type, 2);
362
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
363
errmsg("encrypt error: %d", err)));
366
VARATT_SIZEP(res) = VARHDRSZ + rlen;
367
PG_RETURN_BYTEA_P(res);
370
/* SQL function: pg_decrypt(text, text, text) returns text */
371
PG_FUNCTION_INFO_V1(pg_decrypt);
374
pg_decrypt(PG_FUNCTION_ARGS)
386
if (PG_ARGISNULL(0) || PG_ARGISNULL(1) || PG_ARGISNULL(2))
389
type = PG_GETARG_TEXT_P(2);
390
c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
392
data = PG_GETARG_BYTEA_P(0);
393
key = PG_GETARG_BYTEA_P(1);
394
dlen = VARSIZE(data) - VARHDRSZ;
395
klen = VARSIZE(key) - VARHDRSZ;
397
rlen = px_combo_decrypt_len(c, dlen);
398
res = palloc(VARHDRSZ + rlen);
400
err = px_combo_init(c, VARDATA(key), klen, NULL, 0);
402
err = px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
408
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
409
errmsg("decrypt error: %d", err)));
411
VARATT_SIZEP(res) = VARHDRSZ + rlen;
413
PG_FREE_IF_COPY(data, 0);
414
PG_FREE_IF_COPY(key, 1);
415
PG_FREE_IF_COPY(type, 2);
417
PG_RETURN_BYTEA_P(res);
420
/* SQL function: pg_encrypt(text, text, text) returns text */
421
PG_FUNCTION_INFO_V1(pg_encrypt_iv);
424
pg_encrypt_iv(PG_FUNCTION_ARGS)
438
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
439
|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
442
type = PG_GETARG_TEXT_P(3);
443
c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
445
data = PG_GETARG_BYTEA_P(0);
446
key = PG_GETARG_BYTEA_P(1);
447
iv = PG_GETARG_BYTEA_P(2);
448
dlen = VARSIZE(data) - VARHDRSZ;
449
klen = VARSIZE(key) - VARHDRSZ;
450
ivlen = VARSIZE(iv) - VARHDRSZ;
452
rlen = px_combo_encrypt_len(c, dlen);
453
res = palloc(VARHDRSZ + rlen);
455
err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
457
px_combo_encrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
463
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
464
errmsg("encrypt_iv error: %d", err)));
466
VARATT_SIZEP(res) = VARHDRSZ + rlen;
468
PG_FREE_IF_COPY(data, 0);
469
PG_FREE_IF_COPY(key, 1);
470
PG_FREE_IF_COPY(iv, 2);
471
PG_FREE_IF_COPY(type, 3);
473
PG_RETURN_BYTEA_P(res);
476
/* SQL function: pg_decrypt_iv(text, text, text) returns text */
477
PG_FUNCTION_INFO_V1(pg_decrypt_iv);
480
pg_decrypt_iv(PG_FUNCTION_ARGS)
494
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)
495
|| PG_ARGISNULL(2) || PG_ARGISNULL(3))
498
type = PG_GETARG_TEXT_P(3);
499
c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
501
data = PG_GETARG_BYTEA_P(0);
502
key = PG_GETARG_BYTEA_P(1);
503
iv = PG_GETARG_BYTEA_P(2);
504
dlen = VARSIZE(data) - VARHDRSZ;
505
klen = VARSIZE(key) - VARHDRSZ;
506
ivlen = VARSIZE(iv) - VARHDRSZ;
508
rlen = px_combo_decrypt_len(c, dlen);
509
res = palloc(VARHDRSZ + rlen);
511
err = px_combo_init(c, VARDATA(key), klen, VARDATA(iv), ivlen);
513
px_combo_decrypt(c, VARDATA(data), dlen, VARDATA(res), &rlen);
519
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
520
errmsg("decrypt_iv error: %d", err)));
522
VARATT_SIZEP(res) = VARHDRSZ + rlen;
524
PG_FREE_IF_COPY(data, 0);
525
PG_FREE_IF_COPY(key, 1);
526
PG_FREE_IF_COPY(iv, 2);
527
PG_FREE_IF_COPY(type, 3);
529
PG_RETURN_BYTEA_P(res);
532
/* SQL function: pg_decrypt(text, text, text) returns text */
533
PG_FUNCTION_INFO_V1(pg_cipher_exists);
536
pg_cipher_exists(PG_FUNCTION_ARGS)
544
arg = PG_GETARG_TEXT_P(0);
546
c = find_provider(arg, (PFN) px_find_combo, "Cipher", 1);
550
PG_RETURN_BOOL((c != NULL) ? true : false);
555
find_provider(text *name,
557
char *desc, int silent)
563
buf = downcase_truncate_identifier(VARDATA(name),
564
VARSIZE(name) - VARHDRSZ,
567
err = provider_lookup(buf, &res);
571
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
572
errmsg("%s type does not exist: \"%s\"", desc, buf)));
576
return err ? NULL : res;