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