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