00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include <ctype.h>
00035
00036 #include "parser/scansup.h"
00037 #include "utils/builtins.h"
00038
00039 #include "px.h"
00040 #include "px-crypt.h"
00041 #include "pgcrypto.h"
00042
00043 PG_MODULE_MAGIC;
00044
00045
00046
00047 typedef int (*PFN) (const char *name, void **res);
00048 static void *find_provider(text *name, PFN pf, char *desc, int silent);
00049
00050
00051 PG_FUNCTION_INFO_V1(pg_digest);
00052
00053 Datum
00054 pg_digest(PG_FUNCTION_ARGS)
00055 {
00056 bytea *arg;
00057 text *name;
00058 unsigned len,
00059 hlen;
00060 PX_MD *md;
00061 bytea *res;
00062
00063 name = PG_GETARG_TEXT_P(1);
00064
00065
00066 md = find_provider(name, (PFN) px_find_digest, "Digest", 0);
00067
00068 hlen = px_md_result_size(md);
00069
00070 res = (text *) palloc(hlen + VARHDRSZ);
00071 SET_VARSIZE(res, hlen + VARHDRSZ);
00072
00073 arg = PG_GETARG_BYTEA_P(0);
00074 len = VARSIZE(arg) - VARHDRSZ;
00075
00076 px_md_update(md, (uint8 *) VARDATA(arg), len);
00077 px_md_finish(md, (uint8 *) VARDATA(res));
00078 px_md_free(md);
00079
00080 PG_FREE_IF_COPY(arg, 0);
00081 PG_FREE_IF_COPY(name, 1);
00082
00083 PG_RETURN_BYTEA_P(res);
00084 }
00085
00086
00087 PG_FUNCTION_INFO_V1(pg_hmac);
00088
00089 Datum
00090 pg_hmac(PG_FUNCTION_ARGS)
00091 {
00092 bytea *arg;
00093 bytea *key;
00094 text *name;
00095 unsigned len,
00096 hlen,
00097 klen;
00098 PX_HMAC *h;
00099 bytea *res;
00100
00101 name = PG_GETARG_TEXT_P(2);
00102
00103
00104 h = find_provider(name, (PFN) px_find_hmac, "HMAC", 0);
00105
00106 hlen = px_hmac_result_size(h);
00107
00108 res = (text *) palloc(hlen + VARHDRSZ);
00109 SET_VARSIZE(res, hlen + VARHDRSZ);
00110
00111 arg = PG_GETARG_BYTEA_P(0);
00112 key = PG_GETARG_BYTEA_P(1);
00113 len = VARSIZE(arg) - VARHDRSZ;
00114 klen = VARSIZE(key) - VARHDRSZ;
00115
00116 px_hmac_init(h, (uint8 *) VARDATA(key), klen);
00117 px_hmac_update(h, (uint8 *) VARDATA(arg), len);
00118 px_hmac_finish(h, (uint8 *) VARDATA(res));
00119 px_hmac_free(h);
00120
00121 PG_FREE_IF_COPY(arg, 0);
00122 PG_FREE_IF_COPY(key, 1);
00123 PG_FREE_IF_COPY(name, 2);
00124
00125 PG_RETURN_BYTEA_P(res);
00126 }
00127
00128
00129
00130 PG_FUNCTION_INFO_V1(pg_gen_salt);
00131
00132 Datum
00133 pg_gen_salt(PG_FUNCTION_ARGS)
00134 {
00135 text *arg0 = PG_GETARG_TEXT_PP(0);
00136 int len;
00137 char buf[PX_MAX_SALT_LEN + 1];
00138
00139 text_to_cstring_buffer(arg0, buf, sizeof(buf));
00140 len = px_gen_salt(buf, buf, 0);
00141 if (len < 0)
00142 ereport(ERROR,
00143 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00144 errmsg("gen_salt: %s", px_strerror(len))));
00145
00146 PG_FREE_IF_COPY(arg0, 0);
00147
00148 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
00149 }
00150
00151
00152 PG_FUNCTION_INFO_V1(pg_gen_salt_rounds);
00153
00154 Datum
00155 pg_gen_salt_rounds(PG_FUNCTION_ARGS)
00156 {
00157 text *arg0 = PG_GETARG_TEXT_PP(0);
00158 int rounds = PG_GETARG_INT32(1);
00159 int len;
00160 char buf[PX_MAX_SALT_LEN + 1];
00161
00162 text_to_cstring_buffer(arg0, buf, sizeof(buf));
00163 len = px_gen_salt(buf, buf, rounds);
00164 if (len < 0)
00165 ereport(ERROR,
00166 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00167 errmsg("gen_salt: %s", px_strerror(len))));
00168
00169 PG_FREE_IF_COPY(arg0, 0);
00170
00171 PG_RETURN_TEXT_P(cstring_to_text_with_len(buf, len));
00172 }
00173
00174
00175 PG_FUNCTION_INFO_V1(pg_crypt);
00176
00177 Datum
00178 pg_crypt(PG_FUNCTION_ARGS)
00179 {
00180 text *arg0 = PG_GETARG_TEXT_PP(0);
00181 text *arg1 = PG_GETARG_TEXT_PP(1);
00182 char *buf0,
00183 *buf1,
00184 *cres,
00185 *resbuf;
00186 text *res;
00187
00188 buf0 = text_to_cstring(arg0);
00189 buf1 = text_to_cstring(arg1);
00190
00191 resbuf = palloc0(PX_MAX_CRYPT);
00192
00193 cres = px_crypt(buf0, buf1, resbuf, PX_MAX_CRYPT);
00194
00195 pfree(buf0);
00196 pfree(buf1);
00197
00198 if (cres == NULL)
00199 ereport(ERROR,
00200 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00201 errmsg("crypt(3) returned NULL")));
00202
00203 res = cstring_to_text(cres);
00204
00205 pfree(resbuf);
00206
00207 PG_FREE_IF_COPY(arg0, 0);
00208 PG_FREE_IF_COPY(arg1, 1);
00209
00210 PG_RETURN_TEXT_P(res);
00211 }
00212
00213
00214 PG_FUNCTION_INFO_V1(pg_encrypt);
00215
00216 Datum
00217 pg_encrypt(PG_FUNCTION_ARGS)
00218 {
00219 int err;
00220 bytea *data,
00221 *key,
00222 *res;
00223 text *type;
00224 PX_Combo *c;
00225 unsigned dlen,
00226 klen,
00227 rlen;
00228
00229 type = PG_GETARG_TEXT_P(2);
00230 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00231
00232 data = PG_GETARG_BYTEA_P(0);
00233 key = PG_GETARG_BYTEA_P(1);
00234 dlen = VARSIZE(data) - VARHDRSZ;
00235 klen = VARSIZE(key) - VARHDRSZ;
00236
00237 rlen = px_combo_encrypt_len(c, dlen);
00238 res = palloc(VARHDRSZ + rlen);
00239
00240 err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
00241 if (!err)
00242 err = px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
00243 (uint8 *) VARDATA(res), &rlen);
00244 px_combo_free(c);
00245
00246 PG_FREE_IF_COPY(data, 0);
00247 PG_FREE_IF_COPY(key, 1);
00248 PG_FREE_IF_COPY(type, 2);
00249
00250 if (err)
00251 {
00252 pfree(res);
00253 ereport(ERROR,
00254 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00255 errmsg("encrypt error: %s", px_strerror(err))));
00256 }
00257
00258 SET_VARSIZE(res, VARHDRSZ + rlen);
00259 PG_RETURN_BYTEA_P(res);
00260 }
00261
00262
00263 PG_FUNCTION_INFO_V1(pg_decrypt);
00264
00265 Datum
00266 pg_decrypt(PG_FUNCTION_ARGS)
00267 {
00268 int err;
00269 bytea *data,
00270 *key,
00271 *res;
00272 text *type;
00273 PX_Combo *c;
00274 unsigned dlen,
00275 klen,
00276 rlen;
00277
00278 type = PG_GETARG_TEXT_P(2);
00279 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00280
00281 data = PG_GETARG_BYTEA_P(0);
00282 key = PG_GETARG_BYTEA_P(1);
00283 dlen = VARSIZE(data) - VARHDRSZ;
00284 klen = VARSIZE(key) - VARHDRSZ;
00285
00286 rlen = px_combo_decrypt_len(c, dlen);
00287 res = palloc(VARHDRSZ + rlen);
00288
00289 err = px_combo_init(c, (uint8 *) VARDATA(key), klen, NULL, 0);
00290 if (!err)
00291 err = px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
00292 (uint8 *) VARDATA(res), &rlen);
00293
00294 px_combo_free(c);
00295
00296 if (err)
00297 ereport(ERROR,
00298 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00299 errmsg("decrypt error: %s", px_strerror(err))));
00300
00301 SET_VARSIZE(res, VARHDRSZ + rlen);
00302
00303 PG_FREE_IF_COPY(data, 0);
00304 PG_FREE_IF_COPY(key, 1);
00305 PG_FREE_IF_COPY(type, 2);
00306
00307 PG_RETURN_BYTEA_P(res);
00308 }
00309
00310
00311 PG_FUNCTION_INFO_V1(pg_encrypt_iv);
00312
00313 Datum
00314 pg_encrypt_iv(PG_FUNCTION_ARGS)
00315 {
00316 int err;
00317 bytea *data,
00318 *key,
00319 *iv,
00320 *res;
00321 text *type;
00322 PX_Combo *c;
00323 unsigned dlen,
00324 klen,
00325 ivlen,
00326 rlen;
00327
00328 type = PG_GETARG_TEXT_P(3);
00329 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00330
00331 data = PG_GETARG_BYTEA_P(0);
00332 key = PG_GETARG_BYTEA_P(1);
00333 iv = PG_GETARG_BYTEA_P(2);
00334 dlen = VARSIZE(data) - VARHDRSZ;
00335 klen = VARSIZE(key) - VARHDRSZ;
00336 ivlen = VARSIZE(iv) - VARHDRSZ;
00337
00338 rlen = px_combo_encrypt_len(c, dlen);
00339 res = palloc(VARHDRSZ + rlen);
00340
00341 err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
00342 (uint8 *) VARDATA(iv), ivlen);
00343 if (!err)
00344 err = px_combo_encrypt(c, (uint8 *) VARDATA(data), dlen,
00345 (uint8 *) VARDATA(res), &rlen);
00346
00347 px_combo_free(c);
00348
00349 if (err)
00350 ereport(ERROR,
00351 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00352 errmsg("encrypt_iv error: %s", px_strerror(err))));
00353
00354 SET_VARSIZE(res, VARHDRSZ + rlen);
00355
00356 PG_FREE_IF_COPY(data, 0);
00357 PG_FREE_IF_COPY(key, 1);
00358 PG_FREE_IF_COPY(iv, 2);
00359 PG_FREE_IF_COPY(type, 3);
00360
00361 PG_RETURN_BYTEA_P(res);
00362 }
00363
00364
00365 PG_FUNCTION_INFO_V1(pg_decrypt_iv);
00366
00367 Datum
00368 pg_decrypt_iv(PG_FUNCTION_ARGS)
00369 {
00370 int err;
00371 bytea *data,
00372 *key,
00373 *iv,
00374 *res;
00375 text *type;
00376 PX_Combo *c;
00377 unsigned dlen,
00378 klen,
00379 rlen,
00380 ivlen;
00381
00382 type = PG_GETARG_TEXT_P(3);
00383 c = find_provider(type, (PFN) px_find_combo, "Cipher", 0);
00384
00385 data = PG_GETARG_BYTEA_P(0);
00386 key = PG_GETARG_BYTEA_P(1);
00387 iv = PG_GETARG_BYTEA_P(2);
00388 dlen = VARSIZE(data) - VARHDRSZ;
00389 klen = VARSIZE(key) - VARHDRSZ;
00390 ivlen = VARSIZE(iv) - VARHDRSZ;
00391
00392 rlen = px_combo_decrypt_len(c, dlen);
00393 res = palloc(VARHDRSZ + rlen);
00394
00395 err = px_combo_init(c, (uint8 *) VARDATA(key), klen,
00396 (uint8 *) VARDATA(iv), ivlen);
00397 if (!err)
00398 err = px_combo_decrypt(c, (uint8 *) VARDATA(data), dlen,
00399 (uint8 *) VARDATA(res), &rlen);
00400
00401 px_combo_free(c);
00402
00403 if (err)
00404 ereport(ERROR,
00405 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00406 errmsg("decrypt_iv error: %s", px_strerror(err))));
00407
00408 SET_VARSIZE(res, VARHDRSZ + rlen);
00409
00410 PG_FREE_IF_COPY(data, 0);
00411 PG_FREE_IF_COPY(key, 1);
00412 PG_FREE_IF_COPY(iv, 2);
00413 PG_FREE_IF_COPY(type, 3);
00414
00415 PG_RETURN_BYTEA_P(res);
00416 }
00417
00418
00419 PG_FUNCTION_INFO_V1(pg_random_bytes);
00420
00421 Datum
00422 pg_random_bytes(PG_FUNCTION_ARGS)
00423 {
00424 int err;
00425 int len = PG_GETARG_INT32(0);
00426 bytea *res;
00427
00428 if (len < 1 || len > 1024)
00429 ereport(ERROR,
00430 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00431 errmsg("Length not in range")));
00432
00433 res = palloc(VARHDRSZ + len);
00434 SET_VARSIZE(res, VARHDRSZ + len);
00435
00436
00437 err = px_get_random_bytes((uint8 *) VARDATA(res), len);
00438 if (err < 0)
00439 ereport(ERROR,
00440 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
00441 errmsg("Random generator error: %s", px_strerror(err))));
00442
00443 PG_RETURN_BYTEA_P(res);
00444 }
00445
00446 static void *
00447 find_provider(text *name,
00448 PFN provider_lookup,
00449 char *desc, int silent)
00450 {
00451 void *res;
00452 char *buf;
00453 int err;
00454
00455 buf = downcase_truncate_identifier(VARDATA(name),
00456 VARSIZE(name) - VARHDRSZ,
00457 false);
00458
00459 err = provider_lookup(buf, &res);
00460
00461 if (err && !silent)
00462 ereport(ERROR,
00463 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00464 errmsg("Cannot use \"%s\": %s", buf, px_strerror(err))));
00465
00466 pfree(buf);
00467
00468 return err ? NULL : res;
00469 }