nbtree VACUUM: cope with topparent inconsistencies.
[pgsql.git] / contrib / pgcrypto / pgcrypto.c
blob96447c57577614949cd56bbd31a59fbaf3111139
1 /*
2 * pgcrypto.c
3 * Various cryptographic stuff for PostgreSQL.
5 * Copyright (c) 2001 Marko Kreen
6 * All rights reserved.
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.
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.
29 * contrib/pgcrypto/pgcrypto.c
32 #include "postgres.h"
34 #include <ctype.h>
36 #include "parser/scansup.h"
37 #include "pgcrypto.h"
38 #include "px-crypt.h"
39 #include "px.h"
40 #include "utils/builtins.h"
41 #include "utils/uuid.h"
42 #include "varatt.h"
44 PG_MODULE_MAGIC;
46 /* private stuff */
48 typedef int (*PFN) (const char *name, void **res);
49 static void *find_provider(text *name, PFN provider_lookup, const char *desc,
50 int silent);
52 /* SQL function: hash(bytea, text) returns bytea */
53 PG_FUNCTION_INFO_V1(pg_digest);
55 Datum
56 pg_digest(PG_FUNCTION_ARGS)
58 bytea *arg;
59 text *name;
60 unsigned len,
61 hlen;
62 PX_MD *md;
63 bytea *res;
65 name = PG_GETARG_TEXT_PP(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 SET_VARSIZE(res, hlen + VARHDRSZ);
75 arg = PG_GETARG_BYTEA_PP(0);
76 len = VARSIZE_ANY_EXHDR(arg);
78 px_md_update(md, (uint8 *) VARDATA_ANY(arg), len);
79 px_md_finish(md, (uint8 *) VARDATA(res));
80 px_md_free(md);
82 PG_FREE_IF_COPY(arg, 0);
83 PG_FREE_IF_COPY(name, 1);
85 PG_RETURN_BYTEA_P(res);
88 /* SQL function: hmac(data:bytea, key:bytea, type:text) returns bytea */
89 PG_FUNCTION_INFO_V1(pg_hmac);
91 Datum
92 pg_hmac(PG_FUNCTION_ARGS)
94 bytea *arg;
95 bytea *key;
96 text *name;
97 unsigned len,
98 hlen,
99 klen;
100 PX_HMAC *h;
101 bytea *res;
103 name = PG_GETARG_TEXT_PP(2);
105 /* will give error if fails */
106 h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
108 hlen = px_hmac_result_size(h);
110 res = (text *) palloc(hlen + VARHDRSZ);
111 SET_VARSIZE(res, hlen + VARHDRSZ);
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);
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);
123 PG_FREE_IF_COPY(arg, 0);
124 PG_FREE_IF_COPY(key, 1);
125 PG_FREE_IF_COPY(name, 2);
127 PG_RETURN_BYTEA_P(res);
131 /* SQL function: pg_gen_salt(text) returns text */
132 PG_FUNCTION_INFO_V1(pg_gen_salt);
134 Datum
135 pg_gen_salt(PG_FUNCTION_ARGS)
137 text *arg0 = PG_GETARG_TEXT_PP(0);
138 int len;
139 char buf[PX_MAX_SALT_LEN + 1];
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))));
148 PG_FREE_IF_COPY(arg0, 0);
150 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
153 /* SQL function: pg_gen_salt(text, int4) returns text */
154 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
156 Datum
157 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
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];
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))));
171 PG_FREE_IF_COPY(arg0, 0);
173 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
176 /* SQL function: pg_crypt(psw:text, salt:text) returns text */
177 PG_FUNCTION_INFO_V1(pg_crypt);
179 Datum
180 pg_crypt(PG_FUNCTION_ARGS)
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;
190 buf0 = text_to_cstring(arg0);
191 buf1 = text_to_cstring(arg1);
193 resbuf = palloc0(PX_MAX_CRYPT);
195 cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
197 pfree(buf0);
198 pfree(buf1);
200 if (cres == NULL)
201 ereport(ERROR,
202 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
203 errmsg("crypt(3) returned NULL")));
205 res = cstring_to_text(cres);
207 pfree(resbuf);
209 PG_FREE_IF_COPY(arg0, 0);
210 PG_FREE_IF_COPY(arg1, 1);
212 PG_RETURN_TEXT_P(res);
215 /* SQL function: pg_encrypt(bytea, bytea, text) returns bytea */
216 PG_FUNCTION_INFO_V1(pg_encrypt);
218 Datum
219 pg_encrypt(PG_FUNCTION_ARGS)
221 int err;
222 bytea *data,
223 *key,
224 *res;
225 text *type;
226 PX_Combo *c;
227 unsigned dlen,
228 klen,
229 rlen;
231 type = PG_GETARG_TEXT_PP(2);
232 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
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);
239 rlen = px_combo_encrypt_len(c, dlen);
240 res = palloc(VARHDRSZ + rlen);
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);
248 PG_FREE_IF_COPY(data, 0);
249 PG_FREE_IF_COPY(key, 1);
250 PG_FREE_IF_COPY(type, 2);
252 if (err)
254 pfree(res);
255 ereport(ERROR,
256 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
257 errmsg("encrypt error: %s", px_strerror(err))));
260 SET_VARSIZE(res, VARHDRSZ + rlen);
261 PG_RETURN_BYTEA_P(res);
264 /* SQL function: pg_decrypt(bytea, bytea, text) returns bytea */
265 PG_FUNCTION_INFO_V1(pg_decrypt);
267 Datum
268 pg_decrypt(PG_FUNCTION_ARGS)
270 int err;
271 bytea *data,
272 *key,
273 *res;
274 text *type;
275 PX_Combo *c;
276 unsigned dlen,
277 klen,
278 rlen;
280 type = PG_GETARG_TEXT_PP(2);
281 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
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);
288 rlen = px_combo_decrypt_len(c, dlen);
289 res = palloc(VARHDRSZ + rlen);
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);
296 px_combo_free(c);
298 if (err)
299 ereport(ERROR,
300 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
301 errmsg("decrypt error: %s", px_strerror(err))));
303 SET_VARSIZE(res, VARHDRSZ + rlen);
305 PG_FREE_IF_COPY(data, 0);
306 PG_FREE_IF_COPY(key, 1);
307 PG_FREE_IF_COPY(type, 2);
309 PG_RETURN_BYTEA_P(res);
312 /* SQL function: pg_encrypt_iv(bytea, bytea, bytea, text) returns bytea */
313 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
315 Datum
316 pg_encrypt_iv(PG_FUNCTION_ARGS)
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;
330 type = PG_GETARG_TEXT_PP(3);
331 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
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);
340 rlen = px_combo_encrypt_len(c, dlen);
341 res = palloc(VARHDRSZ + rlen);
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);
349 px_combo_free(c);
351 if (err)
352 ereport(ERROR,
353 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
354 errmsg("encrypt_iv error: %s", px_strerror(err))));
356 SET_VARSIZE(res, VARHDRSZ + rlen);
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);
363 PG_RETURN_BYTEA_P(res);
366 /* SQL function: pg_decrypt_iv(bytea, bytea, bytea, text) returns bytea */
367 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
369 Datum
370 pg_decrypt_iv(PG_FUNCTION_ARGS)
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;
384 type = PG_GETARG_TEXT_PP(3);
385 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
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);
394 rlen = px_combo_decrypt_len(c, dlen);
395 res = palloc(VARHDRSZ + rlen);
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);
403 px_combo_free(c);
405 if (err)
406 ereport(ERROR,
407 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
408 errmsg("decrypt_iv error: %s", px_strerror(err))));
410 SET_VARSIZE(res, VARHDRSZ + rlen);
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);
417 PG_RETURN_BYTEA_P(res);
420 /* SQL function: pg_random_bytes(int4) returns bytea */
421 PG_FUNCTION_INFO_V1(pg_random_bytes);
423 Datum
424 pg_random_bytes(PG_FUNCTION_ARGS)
426 int len = PG_GETARG_INT32(0);
427 bytea *res;
429 if (len < 1 || len > 1024)
430 ereport(ERROR,
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 if (!pg_strong_random(VARDATA(res), len))
439 px_THROW_ERROR(PXE_NO_RANDOM);
441 PG_RETURN_BYTEA_P(res);
444 /* SQL function: gen_random_uuid() returns uuid */
445 PG_FUNCTION_INFO_V1(pg_random_uuid);
447 Datum
448 pg_random_uuid(PG_FUNCTION_ARGS)
450 /* redirect to built-in function */
451 return gen_random_uuid(fcinfo);
454 static void *
455 find_provider(text *name,
456 PFN provider_lookup,
457 const char *desc, int silent)
459 void *res;
460 char *buf;
461 int err;
463 buf = downcase_truncate_identifier(VARDATA_ANY(name),
464 VARSIZE_ANY_EXHDR(name),
465 false);
467 err = provider_lookup(buf, &res);
469 if (err && !silent)
470 ereport(ERROR,
471 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
472 errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
474 pfree(buf);
476 return err ? NULL : res;