1 /*
2 * pgcrypto.c
3 * Various cryptographic stuff for PostgreSQL.
4 *
5 * Copyright (c) 2001 Marko Kreen
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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
27 * SUCH DAMAGE.
28 *
29 * contrib/pgcrypto/pgcrypto.c
30 */
31
32 #include "postgres.h"
33
34 #include <ctype.h>
35
36 #include "parser/scansup.h"
37 #include "utils/backend_random.h"
38 #include "utils/builtins.h"
39 #include "utils/uuid.h"
40
41 #include "px.h"
42 #include "px-crypt.h"
43 #include "pgcrypto.h"
44
45 PG_MODULE_MAGIC;
46
47 /* private stuff */
48
49 typedef int (*PFN) (const char *name, void **res);
50 static void *find_provider(text *name, PFN pf, char *desc, int silent);
51
52 /* SQL function: hash(bytea, text) returns bytea */
53 PG_FUNCTION_INFO_V1(pg_digest);
54
55 Datum
pg_digest(PG_FUNCTION_ARGS)56 pg_digest(PG_FUNCTION_ARGS)
57 {
58 bytea *arg;
59 text *name;
60 unsigned len,
61 hlen;
62 PX_MD *md;
63 bytea *res;
64
65 name = PG_GETARG_TEXT_PP(1);
66
67 /* will give error if fails */
68 md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
69
70 hlen = px_md_result_size(md);
71
72 res = (text *) palloc(hlen + VARHDRSZ);
73 SET_VARSIZE(res, hlen + VARHDRSZ);
74
75 arg = PG_GETARG_BYTEA_PP(0);
76 len = VARSIZE_ANY_EXHDR(arg);
77
78 px_md_update(md, (uint8 *) VARDATA_ANY(arg), len);
79 px_md_finish(md, (uint8 *) VARDATA(res));
80 px_md_free(md);
81
82 PG_FREE_IF_COPY(arg, 0);
83 PG_FREE_IF_COPY(name, 1);
84
85 PG_RETURN_BYTEA_P(res);
86 }
87
88 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
89 PG_FUNCTION_INFO_V1(pg_hmac);
90
91 Datum
pg_hmac(PG_FUNCTION_ARGS)92 pg_hmac(PG_FUNCTION_ARGS)
93 {
94 bytea *arg;
95 bytea *key;
96 text *name;
97 unsigned len,
98 hlen,
99 klen;
100 PX_HMAC *h;
101 bytea *res;
102
103 name = PG_GETARG_TEXT_PP(2);
104
105 /* will give error if fails */
106 h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
107
108 hlen = px_hmac_result_size(h);
109
110 res = (text *) palloc(hlen + VARHDRSZ);
111 SET_VARSIZE(res, hlen + VARHDRSZ);
112
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);
117
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));
121 px_hmac_free(h);
122
123 PG_FREE_IF_COPY(arg, 0);
124 PG_FREE_IF_COPY(key, 1);
125 PG_FREE_IF_COPY(name, 2);
126
127 PG_RETURN_BYTEA_P(res);
128 }
129
130
131 /* SQL function: pg_gen_salt(text) returns text */
132 PG_FUNCTION_INFO_V1(pg_gen_salt);
133
134 Datum
pg_gen_salt(PG_FUNCTION_ARGS)135 pg_gen_salt(PG_FUNCTION_ARGS)
136 {
137 text *arg0 = PG_GETARG_TEXT_PP(0);
138 int len;
139 char buf[PX_MAX_SALT_LEN + 1];
140
141 text_to_cstring_buffer(arg0, buf, sizeof(buf));
142 len = px_gen_salt(buf, buf, 0);
143 if (len < 0)
144 ereport(ERROR,
145 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
146 errmsg("gen_salt: %s", px_strerror(len))));
147
148 PG_FREE_IF_COPY(arg0, 0);
149
150 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
151 }
152
153 /* SQL function: pg_gen_salt(text, int4) returns text */
154 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
155
156 Datum
pg_gen_salt_rounds(PG_FUNCTION_ARGS)157 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
158 {
159 text *arg0 = PG_GETARG_TEXT_PP(0);
160 int rounds = PG_GETARG_INT32(1);
161 int len;
162 char buf[PX_MAX_SALT_LEN + 1];
163
164 text_to_cstring_buffer(arg0, buf, sizeof(buf));
165 len = px_gen_salt(buf, buf, rounds);
166 if (len < 0)
167 ereport(ERROR,
168 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
169 errmsg("gen_salt: %s", px_strerror(len))));
170
171 PG_FREE_IF_COPY(arg0, 0);
172
173 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
174 }
175
176 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
177 PG_FUNCTION_INFO_V1(pg_crypt);
178
179 Datum
pg_crypt(PG_FUNCTION_ARGS)180 pg_crypt(PG_FUNCTION_ARGS)
181 {
182 text *arg0 = PG_GETARG_TEXT_PP(0);
183 text *arg1 = PG_GETARG_TEXT_PP(1);
184 char *buf0,
185 *buf1,
186 *cres,
187 *resbuf;
188 text *res;
189
190 buf0 = text_to_cstring(arg0);
191 buf1 = text_to_cstring(arg1);
192
193 resbuf = palloc0(PX_MAX_CRYPT);
194
195 cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
196
197 pfree(buf0);
198 pfree(buf1);
199
200 if (cres == NULL)
201 ereport(ERROR,
202 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
203 errmsg("crypt(3) returned NULL")));
204
205 res = cstring_to_text(cres);
206
207 pfree(resbuf);
208
209 PG_FREE_IF_COPY(arg0, 0);
210 PG_FREE_IF_COPY(arg1, 1);
211
212 PG_RETURN_TEXT_P(res);
213 }
214
215 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
216 PG_FUNCTION_INFO_V1(pg_encrypt);
217
218 Datum
pg_encrypt(PG_FUNCTION_ARGS)219 pg_encrypt(PG_FUNCTION_ARGS)
220 {
221 int err;
222 bytea *data,
223 *key,
224 *res;
225 text *type;
226 PX_Combo *c;
227 unsigned dlen,
228 klen,
229 rlen;
230
231 type = PG_GETARG_TEXT_PP(2);
232 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
233
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);
238
239 rlen = px_combo_encrypt_len(c, dlen);
240 res = palloc(VARHDRSZ + rlen);
241
242 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
243 if (!err)
244 err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
245 (uint8 *) VARDATA(res), &rlen);
246 px_combo_free(c);
247
248 PG_FREE_IF_COPY(data, 0);
249 PG_FREE_IF_COPY(key, 1);
250 PG_FREE_IF_COPY(type, 2);
251
252 if (err)
253 {
254 pfree(res);
255 ereport(ERROR,
256 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
257 errmsg("encrypt error: %s", px_strerror(err))));
258 }
259
260 SET_VARSIZE(res, VARHDRSZ + rlen);
261 PG_RETURN_BYTEA_P(res);
262 }
263
264 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
265 PG_FUNCTION_INFO_V1(pg_decrypt);
266
267 Datum
pg_decrypt(PG_FUNCTION_ARGS)268 pg_decrypt(PG_FUNCTION_ARGS)
269 {
270 int err;
271 bytea *data,
272 *key,
273 *res;
274 text *type;
275 PX_Combo *c;
276 unsigned dlen,
277 klen,
278 rlen;
279
280 type = PG_GETARG_TEXT_PP(2);
281 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
282
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);
287
288 rlen = px_combo_decrypt_len(c, dlen);
289 res = palloc(VARHDRSZ + rlen);
290
291 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen, NULL, 0);
292 if (!err)
293 err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
294 (uint8 *) VARDATA(res), &rlen);
295
296 px_combo_free(c);
297
298 if (err)
299 ereport(ERROR,
300 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
301 errmsg("decrypt error: %s", px_strerror(err))));
302
303 SET_VARSIZE(res, VARHDRSZ + rlen);
304
305 PG_FREE_IF_COPY(data, 0);
306 PG_FREE_IF_COPY(key, 1);
307 PG_FREE_IF_COPY(type, 2);
308
309 PG_RETURN_BYTEA_P(res);
310 }
311
312 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
313 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
314
315 Datum
pg_encrypt_iv(PG_FUNCTION_ARGS)316 pg_encrypt_iv(PG_FUNCTION_ARGS)
317 {
318 int err;
319 bytea *data,
320 *key,
321 *iv,
322 *res;
323 text *type;
324 PX_Combo *c;
325 unsigned dlen,
326 klen,
327 ivlen,
328 rlen;
329
330 type = PG_GETARG_TEXT_PP(3);
331 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
332
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);
339
340 rlen = px_combo_encrypt_len(c, dlen);
341 res = palloc(VARHDRSZ + rlen);
342
343 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
344 (uint8 *) VARDATA_ANY(iv), ivlen);
345 if (!err)
346 err = px_combo_encrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
347 (uint8 *) VARDATA(res), &rlen);
348
349 px_combo_free(c);
350
351 if (err)
352 ereport(ERROR,
353 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
354 errmsg("encrypt_iv error: %s", px_strerror(err))));
355
356 SET_VARSIZE(res, VARHDRSZ + rlen);
357
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);
362
363 PG_RETURN_BYTEA_P(res);
364 }
365
366 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
367 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
368
369 Datum
pg_decrypt_iv(PG_FUNCTION_ARGS)370 pg_decrypt_iv(PG_FUNCTION_ARGS)
371 {
372 int err;
373 bytea *data,
374 *key,
375 *iv,
376 *res;
377 text *type;
378 PX_Combo *c;
379 unsigned dlen,
380 klen,
381 rlen,
382 ivlen;
383
384 type = PG_GETARG_TEXT_PP(3);
385 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
386
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);
393
394 rlen = px_combo_decrypt_len(c, dlen);
395 res = palloc(VARHDRSZ + rlen);
396
397 err = px_combo_init(c, (uint8 *) VARDATA_ANY(key), klen,
398 (uint8 *) VARDATA_ANY(iv), ivlen);
399 if (!err)
400 err = px_combo_decrypt(c, (uint8 *) VARDATA_ANY(data), dlen,
401 (uint8 *) VARDATA(res), &rlen);
402
403 px_combo_free(c);
404
405 if (err)
406 ereport(ERROR,
407 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
408 errmsg("decrypt_iv error: %s", px_strerror(err))));
409
410 SET_VARSIZE(res, VARHDRSZ + rlen);
411
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);
416
417 PG_RETURN_BYTEA_P(res);
418 }
419
420 /* SQL function: pg_random_bytes(int4) returns bytea */
421 PG_FUNCTION_INFO_V1(pg_random_bytes);
422
423 Datum
pg_random_bytes(PG_FUNCTION_ARGS)424 pg_random_bytes(PG_FUNCTION_ARGS)
425 {
426 #ifdef HAVE_STRONG_RANDOM
427 int len = PG_GETARG_INT32(0);
428 bytea *res;
429
430 if (len < 1 || len > 1024)
431 ereport(ERROR,
432 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
433 errmsg("Length not in range")));
434
435 res = palloc(VARHDRSZ + len);
436 SET_VARSIZE(res, VARHDRSZ + len);
437
438 /* generate result */
439 if (!pg_strong_random(VARDATA(res), len))
440 px_THROW_ERROR(PXE_NO_RANDOM);
441
442 PG_RETURN_BYTEA_P(res);
443 #else
444 px_THROW_ERROR(PXE_NO_RANDOM);
445 #endif
446 }
447
448 /* SQL function: gen_random_uuid() returns uuid */
449 PG_FUNCTION_INFO_V1(pg_random_uuid);
450
451 Datum
pg_random_uuid(PG_FUNCTION_ARGS)452 pg_random_uuid(PG_FUNCTION_ARGS)
453 {
454 #ifdef HAVE_STRONG_RANDOM
455 uint8 *buf = (uint8 *) palloc(UUID_LEN);
456
457 /* Generate random bits. */
458 if (!pg_backend_random((char *) buf, UUID_LEN))
459 px_THROW_ERROR(PXE_NO_RANDOM);
460
461 /*
462 * Set magic numbers for a "version 4" (pseudorandom) UUID, see
463 * http://tools.ietf.org/html/rfc4122#section-4.4
464 */
465 buf[6] = (buf[6] & 0x0f) | 0x40; /* "version" field */
466 buf[8] = (buf[8] & 0x3f) | 0x80; /* "variant" field */
467
468 PG_RETURN_UUID_P((pg_uuid_t *) buf);
469 #else
470 px_THROW_ERROR(PXE_NO_RANDOM);
471 #endif
472 }
473
474 static void *
find_provider(text * name,PFN provider_lookup,char * desc,int silent)475 find_provider(text *name,
476 PFN provider_lookup,
477 char *desc, int silent)
478 {
479 void *res;
480 char *buf;
481 int err;
482
483 buf = downcase_truncate_identifier(VARDATA_ANY(name),
484 VARSIZE_ANY_EXHDR(name),
485 false);
486
487 err = provider_lookup(buf, &res);
488
489 if (err && !silent)
490 ereport(ERROR,
491 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
492 errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
493
494 pfree(buf);
495
496 return err ? NULL : res;
497 }
498