Now that we have non-Latin1 SGML detection, restore Latin1 chars
[pgsql.git] / contrib / pgcrypto / px.c
blobd35ccca77746d8dba8ffc360ea8b90c90bba297c
1 /*
2 * px.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/px.c
32 #include "postgres.h"
34 #include "px.h"
36 struct error_desc
38 int err;
39 const char *desc;
42 static const struct error_desc px_err_list[] = {
43 {PXE_OK, "Everything ok"},
44 {PXE_NO_HASH, "No such hash algorithm"},
45 {PXE_NO_CIPHER, "No such cipher algorithm"},
46 {PXE_BAD_OPTION, "Unknown option"},
47 {PXE_BAD_FORMAT, "Badly formatted type"},
48 {PXE_KEY_TOO_BIG, "Key was too big"},
49 {PXE_CIPHER_INIT, "Cipher cannot be initialized"},
50 {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
51 {PXE_BUG, "pgcrypto bug"},
52 {PXE_ARGUMENT_ERROR, "Illegal argument to function"},
53 {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
54 {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
55 {PXE_NO_RANDOM, "Failed to generate strong random bits"},
56 {PXE_DECRYPT_FAILED, "Decryption failed"},
57 {PXE_ENCRYPT_FAILED, "Encryption failed"},
58 {PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"},
59 {PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"},
60 {PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"},
61 {PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"},
62 {PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"},
63 {PXE_PGP_COMPRESSION_ERROR, "Compression error"},
64 {PXE_PGP_NOT_TEXT, "Not text data"},
65 {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"},
66 {PXE_PGP_MATH_FAILED, "Math operation failed"},
67 {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"},
68 {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"},
69 {PXE_PGP_WRONG_KEY, "Wrong key"},
70 {PXE_PGP_MULTIPLE_KEYS,
71 "Several keys given - pgcrypto does not handle keyring"},
72 {PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"},
73 {PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"},
74 {PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"},
75 {PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"},
76 {PXE_PGP_NO_USABLE_KEY, "No encryption key found"},
77 {PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"},
78 {PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
79 {PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
80 {PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
82 {0, NULL},
86 * Call ereport(ERROR, ...), with an error code and message corresponding to
87 * the PXE_* error code given as argument.
89 * This is similar to px_strerror(err), but for some errors, we fill in the
90 * error code and detail fields more appropriately.
92 void
93 px_THROW_ERROR(int err)
95 if (err == PXE_NO_RANDOM)
97 ereport(ERROR,
98 (errcode(ERRCODE_INTERNAL_ERROR),
99 errmsg("could not generate a random number")));
101 else
103 /* For other errors, use the message from the above list. */
104 ereport(ERROR,
105 (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
106 errmsg("%s", px_strerror(err))));
110 const char *
111 px_strerror(int err)
113 const struct error_desc *e;
115 for (e = px_err_list; e->desc; e++)
116 if (e->err == err)
117 return e->desc;
118 return "Bad error code";
121 /* memset that must not be optimized away */
122 void
123 px_memset(void *ptr, int c, size_t len)
125 memset(ptr, c, len);
128 const char *
129 px_resolve_alias(const PX_Alias *list, const char *name)
131 while (list->name)
133 if (pg_strcasecmp(list->alias, name) == 0)
134 return list->name;
135 list++;
137 return name;
140 static void (*debug_handler) (const char *) = NULL;
142 void
143 px_set_debug_handler(void (*handler) (const char *))
145 debug_handler = handler;
148 void
149 px_debug(const char *fmt,...)
151 va_list ap;
153 va_start(ap, fmt);
154 if (debug_handler)
156 char buf[512];
158 vsnprintf(buf, sizeof(buf), fmt, ap);
159 debug_handler(buf);
161 va_end(ap);
165 * combo - cipher + padding (+ checksum)
168 static unsigned
169 combo_encrypt_len(PX_Combo *cx, unsigned dlen)
171 return dlen + 512;
174 static unsigned
175 combo_decrypt_len(PX_Combo *cx, unsigned dlen)
177 return dlen;
180 static int
181 combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
182 const uint8 *iv, unsigned ivlen)
184 int err;
185 unsigned ks,
186 ivs;
187 PX_Cipher *c = cx->cipher;
188 uint8 *ivbuf = NULL;
189 uint8 *keybuf;
191 ks = px_cipher_key_size(c);
193 ivs = px_cipher_iv_size(c);
194 if (ivs > 0)
196 ivbuf = palloc0(ivs);
197 if (ivlen > ivs)
198 memcpy(ivbuf, iv, ivs);
199 else if (ivlen > 0)
200 memcpy(ivbuf, iv, ivlen);
203 if (klen > ks)
204 klen = ks;
205 keybuf = palloc0(ks);
206 memcpy(keybuf, key, klen);
208 err = px_cipher_init(c, keybuf, klen, ivbuf);
210 if (ivbuf)
211 pfree(ivbuf);
212 pfree(keybuf);
214 return err;
217 static int
218 combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
219 uint8 *res, unsigned *rlen)
221 return px_cipher_encrypt(cx->cipher, cx->padding, data, dlen, res, rlen);
224 static int
225 combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
226 uint8 *res, unsigned *rlen)
228 return px_cipher_decrypt(cx->cipher, cx->padding, data, dlen, res, rlen);
231 static void
232 combo_free(PX_Combo *cx)
234 if (cx->cipher)
235 px_cipher_free(cx->cipher);
236 px_memset(cx, 0, sizeof(*cx));
237 pfree(cx);
240 /* PARSER */
242 static int
243 parse_cipher_name(char *full, char **cipher, char **pad)
245 char *p,
246 *p2,
249 *cipher = full;
250 *pad = NULL;
252 p = strchr(full, '/');
253 if (p != NULL)
254 *p++ = 0;
255 while (p != NULL)
257 if ((q = strchr(p, '/')) != NULL)
258 *q++ = 0;
260 if (!*p)
262 p = q;
263 continue;
265 p2 = strchr(p, ':');
266 if (p2 != NULL)
268 *p2++ = 0;
269 if (strcmp(p, "pad") == 0)
270 *pad = p2;
271 else
272 return PXE_BAD_OPTION;
274 else
275 return PXE_BAD_FORMAT;
277 p = q;
279 return 0;
282 /* provider */
285 px_find_combo(const char *name, PX_Combo **res)
287 int err;
288 char *buf,
289 *s_cipher,
290 *s_pad;
292 PX_Combo *cx;
294 cx = palloc0(sizeof(*cx));
295 buf = pstrdup(name);
297 err = parse_cipher_name(buf, &s_cipher, &s_pad);
298 if (err)
300 pfree(buf);
301 pfree(cx);
302 return err;
305 err = px_find_cipher(s_cipher, &cx->cipher);
306 if (err)
307 goto err1;
309 if (s_pad != NULL)
311 if (strcmp(s_pad, "pkcs") == 0)
312 cx->padding = 1;
313 else if (strcmp(s_pad, "none") == 0)
314 cx->padding = 0;
315 else
316 goto err1;
318 else
319 cx->padding = 1;
321 cx->init = combo_init;
322 cx->encrypt = combo_encrypt;
323 cx->decrypt = combo_decrypt;
324 cx->encrypt_len = combo_encrypt_len;
325 cx->decrypt_len = combo_decrypt_len;
326 cx->free = combo_free;
328 pfree(buf);
330 *res = cx;
332 return 0;
334 err1:
335 if (cx->cipher)
336 px_cipher_free(cx->cipher);
337 pfree(cx);
338 pfree(buf);
339 return PXE_NO_CIPHER;