~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to contrib/pgcrypto/pgcrypto.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * $PostgreSQL$
 
30
 */
 
31
 
 
32
#include "postgres.h"
 
33
 
 
34
#include <ctype.h>
 
35
 
 
36
#include "fmgr.h"
 
37
#include "parser/scansup.h"
 
38
#include "utils/builtins.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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
                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
 
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
                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
 
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
static void *
 
448
find_provider(text *name,
 
449
                          PFN provider_lookup,
 
450
                          char *desc, int silent)
 
451
{
 
452
        void       *res;
 
453
        char       *buf;
 
454
        int                     err;
 
455
 
 
456
        buf = downcase_truncate_identifier(VARDATA(name),
 
457
                                                                           VARSIZE(name) - VARHDRSZ,
 
458
                                                                           false);
 
459
 
 
460
        err = provider_lookup(buf, &res);
 
461
 
 
462
        if (err && !silent)
 
463
                ereport(ERROR,
 
464
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
465
                                 errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
 
466
 
 
467
        pfree(buf);
 
468
 
 
469
        return err ? NULL : res;
 
470
}