Header And Logo

PostgreSQL
| The world's most advanced open source database.

px.c

Go to the documentation of this file.
00001 /*
00002  * px.c
00003  *      Various cryptographic stuff for PostgreSQL.
00004  *
00005  * Copyright (c) 2001 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/px.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "px.h"
00035 
00036 struct error_desc
00037 {
00038     int         err;
00039     const char *desc;
00040 };
00041 
00042 static const struct error_desc px_err_list[] = {
00043     {PXE_OK, "Everything ok"},
00044     {PXE_ERR_GENERIC, "Some PX error (not specified)"},
00045     {PXE_NO_HASH, "No such hash algorithm"},
00046     {PXE_NO_CIPHER, "No such cipher algorithm"},
00047     {PXE_NOTBLOCKSIZE, "Data not a multiple of block size"},
00048     {PXE_BAD_OPTION, "Unknown option"},
00049     {PXE_BAD_FORMAT, "Badly formatted type"},
00050     {PXE_KEY_TOO_BIG, "Key was too big"},
00051     {PXE_CIPHER_INIT, "Cipher cannot be initalized ?"},
00052     {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
00053     {PXE_DEV_READ_ERROR, "Error reading from random device"},
00054     {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"},
00055     {PXE_BUG, "pgcrypto bug"},
00056     {PXE_ARGUMENT_ERROR, "Illegal argument to function"},
00057     {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
00058     {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
00059     {PXE_MCRYPT_INTERNAL, "mcrypt internal error"},
00060     {PXE_NO_RANDOM, "No strong random source"},
00061     {PXE_DECRYPT_FAILED, "Decryption failed"},
00062     {PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"},
00063     {PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"},
00064     {PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"},
00065     {PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"},
00066     {PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"},
00067     {PXE_PGP_COMPRESSION_ERROR, "Compression error"},
00068     {PXE_PGP_NOT_TEXT, "Not text data"},
00069     {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"},
00070     {PXE_PGP_NO_BIGNUM,
00071         "public-key functions disabled - "
00072     "pgcrypto needs OpenSSL for bignums"},
00073     {PXE_PGP_MATH_FAILED, "Math operation failed"},
00074     {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"},
00075     {PXE_PGP_RSA_UNSUPPORTED, "pgcrypto does not support RSA keys"},
00076     {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"},
00077     {PXE_PGP_WRONG_KEY, "Wrong key"},
00078     {PXE_PGP_MULTIPLE_KEYS,
00079     "Several keys given - pgcrypto does not handle keyring"},
00080     {PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"},
00081     {PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"},
00082     {PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"},
00083     {PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"},
00084     {PXE_PGP_NO_USABLE_KEY, "No encryption key found"},
00085     {PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"},
00086     {PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
00087     {PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
00088     {PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
00089 
00090     /* fake this as PXE_PGP_CORRUPT_DATA */
00091     {PXE_MBUF_SHORT_READ, "Corrupt data"},
00092 
00093     {0, NULL},
00094 };
00095 
00096 const char *
00097 px_strerror(int err)
00098 {
00099     const struct error_desc *e;
00100 
00101     for (e = px_err_list; e->desc; e++)
00102         if (e->err == err)
00103             return e->desc;
00104     return "Bad error code";
00105 }
00106 
00107 
00108 const char *
00109 px_resolve_alias(const PX_Alias *list, const char *name)
00110 {
00111     while (list->name)
00112     {
00113         if (pg_strcasecmp(list->alias, name) == 0)
00114             return list->name;
00115         list++;
00116     }
00117     return name;
00118 }
00119 
00120 static void (*debug_handler) (const char *) = NULL;
00121 
00122 void
00123 px_set_debug_handler(void (*handler) (const char *))
00124 {
00125     debug_handler = handler;
00126 }
00127 
00128 void
00129 px_debug(const char *fmt,...)
00130 {
00131     va_list     ap;
00132 
00133     va_start(ap, fmt);
00134     if (debug_handler)
00135     {
00136         char        buf[512];
00137 
00138         vsnprintf(buf, sizeof(buf), fmt, ap);
00139         debug_handler(buf);
00140     }
00141     va_end(ap);
00142 }
00143 
00144 /*
00145  * combo - cipher + padding (+ checksum)
00146  */
00147 
00148 static unsigned
00149 combo_encrypt_len(PX_Combo *cx, unsigned dlen)
00150 {
00151     return dlen + 512;
00152 }
00153 
00154 static unsigned
00155 combo_decrypt_len(PX_Combo *cx, unsigned dlen)
00156 {
00157     return dlen;
00158 }
00159 
00160 static int
00161 combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
00162            const uint8 *iv, unsigned ivlen)
00163 {
00164     int         err;
00165     unsigned    ks,
00166                 ivs;
00167     PX_Cipher  *c = cx->cipher;
00168     uint8      *ivbuf = NULL;
00169     uint8      *keybuf;
00170 
00171     ks = px_cipher_key_size(c);
00172 
00173     ivs = px_cipher_iv_size(c);
00174     if (ivs > 0)
00175     {
00176         ivbuf = px_alloc(ivs);
00177         memset(ivbuf, 0, ivs);
00178         if (ivlen > ivs)
00179             memcpy(ivbuf, iv, ivs);
00180         else
00181             memcpy(ivbuf, iv, ivlen);
00182     }
00183 
00184     if (klen > ks)
00185         klen = ks;
00186     keybuf = px_alloc(ks);
00187     memset(keybuf, 0, ks);
00188     memcpy(keybuf, key, klen);
00189 
00190     err = px_cipher_init(c, keybuf, klen, ivbuf);
00191 
00192     if (ivbuf)
00193         px_free(ivbuf);
00194     px_free(keybuf);
00195 
00196     return err;
00197 }
00198 
00199 static int
00200 combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
00201               uint8 *res, unsigned *rlen)
00202 {
00203     int         err = 0;
00204     uint8      *bbuf;
00205     unsigned    bs,
00206                 bpos,
00207                 i,
00208                 pad;
00209 
00210     PX_Cipher  *c = cx->cipher;
00211 
00212     bbuf = NULL;
00213     bs = px_cipher_block_size(c);
00214 
00215     /* encrypt */
00216     if (bs > 1)
00217     {
00218         bbuf = px_alloc(bs * 4);
00219         bpos = dlen % bs;
00220         *rlen = dlen - bpos;
00221         memcpy(bbuf, data + *rlen, bpos);
00222 
00223         /* encrypt full-block data */
00224         if (*rlen)
00225         {
00226             err = px_cipher_encrypt(c, data, *rlen, res);
00227             if (err)
00228                 goto out;
00229         }
00230 
00231         /* bbuf has now bpos bytes of stuff */
00232         if (cx->padding)
00233         {
00234             pad = bs - (bpos % bs);
00235             for (i = 0; i < pad; i++)
00236                 bbuf[bpos++] = pad;
00237         }
00238         else if (bpos % bs)
00239         {
00240             /* ERROR? */
00241             pad = bs - (bpos % bs);
00242             for (i = 0; i < pad; i++)
00243                 bbuf[bpos++] = 0;
00244         }
00245 
00246         /* encrypt the rest - pad */
00247         if (bpos)
00248         {
00249             err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen);
00250             *rlen += bpos;
00251         }
00252     }
00253     else
00254     {
00255         /* stream cipher/mode - no pad needed */
00256         err = px_cipher_encrypt(c, data, dlen, res);
00257         if (err)
00258             goto out;
00259         *rlen = dlen;
00260     }
00261 out:
00262     if (bbuf)
00263         px_free(bbuf);
00264 
00265     return err;
00266 }
00267 
00268 static int
00269 combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
00270               uint8 *res, unsigned *rlen)
00271 {
00272     unsigned    bs,
00273                 i,
00274                 pad;
00275     unsigned    pad_ok;
00276 
00277     PX_Cipher  *c = cx->cipher;
00278 
00279     /* decide whether zero-length input is allowed */
00280     if (dlen == 0)
00281     {
00282         /* with padding, empty ciphertext is not allowed */
00283         if (cx->padding)
00284             return PXE_DECRYPT_FAILED;
00285 
00286         /* without padding, report empty result */
00287         *rlen = 0;
00288         return 0;
00289     }
00290 
00291     bs = px_cipher_block_size(c);
00292     if (bs > 1 && (dlen % bs) != 0)
00293         goto block_error;
00294 
00295     /* decrypt */
00296     *rlen = dlen;
00297     px_cipher_decrypt(c, data, dlen, res);
00298 
00299     /* unpad */
00300     if (bs > 1 && cx->padding)
00301     {
00302         pad = res[*rlen - 1];
00303         pad_ok = 0;
00304         if (pad > 0 && pad <= bs && pad <= *rlen)
00305         {
00306             pad_ok = 1;
00307             for (i = *rlen - pad; i < *rlen; i++)
00308                 if (res[i] != pad)
00309                 {
00310                     pad_ok = 0;
00311                     break;
00312                 }
00313         }
00314 
00315         if (pad_ok)
00316             *rlen -= pad;
00317     }
00318 
00319     return 0;
00320 
00321 block_error:
00322     return PXE_NOTBLOCKSIZE;
00323 }
00324 
00325 static void
00326 combo_free(PX_Combo *cx)
00327 {
00328     if (cx->cipher)
00329         px_cipher_free(cx->cipher);
00330     memset(cx, 0, sizeof(*cx));
00331     px_free(cx);
00332 }
00333 
00334 /* PARSER */
00335 
00336 static int
00337 parse_cipher_name(char *full, char **cipher, char **pad)
00338 {
00339     char       *p,
00340                *p2,
00341                *q;
00342 
00343     *cipher = full;
00344     *pad = NULL;
00345 
00346     p = strchr(full, '/');
00347     if (p != NULL)
00348         *p++ = 0;
00349     while (p != NULL)
00350     {
00351         if ((q = strchr(p, '/')) != NULL)
00352             *q++ = 0;
00353 
00354         if (!*p)
00355         {
00356             p = q;
00357             continue;
00358         }
00359         p2 = strchr(p, ':');
00360         if (p2 != NULL)
00361         {
00362             *p2++ = 0;
00363             if (strcmp(p, "pad") == 0)
00364                 *pad = p2;
00365             else
00366                 return PXE_BAD_OPTION;
00367         }
00368         else
00369             return PXE_BAD_FORMAT;
00370 
00371         p = q;
00372     }
00373     return 0;
00374 }
00375 
00376 /* provider */
00377 
00378 int
00379 px_find_combo(const char *name, PX_Combo **res)
00380 {
00381     int         err;
00382     char       *buf,
00383                *s_cipher,
00384                *s_pad;
00385 
00386     PX_Combo   *cx;
00387 
00388     cx = px_alloc(sizeof(*cx));
00389     memset(cx, 0, sizeof(*cx));
00390 
00391     buf = px_alloc(strlen(name) + 1);
00392     strcpy(buf, name);
00393 
00394     err = parse_cipher_name(buf, &s_cipher, &s_pad);
00395     if (err)
00396     {
00397         px_free(buf);
00398         px_free(cx);
00399         return err;
00400     }
00401 
00402     err = px_find_cipher(s_cipher, &cx->cipher);
00403     if (err)
00404         goto err1;
00405 
00406     if (s_pad != NULL)
00407     {
00408         if (strcmp(s_pad, "pkcs") == 0)
00409             cx->padding = 1;
00410         else if (strcmp(s_pad, "none") == 0)
00411             cx->padding = 0;
00412         else
00413             goto err1;
00414     }
00415     else
00416         cx->padding = 1;
00417 
00418     cx->init = combo_init;
00419     cx->encrypt = combo_encrypt;
00420     cx->decrypt = combo_decrypt;
00421     cx->encrypt_len = combo_encrypt_len;
00422     cx->decrypt_len = combo_decrypt_len;
00423     cx->free = combo_free;
00424 
00425     px_free(buf);
00426 
00427     *res = cx;
00428 
00429     return 0;
00430 
00431 err1:
00432     if (cx->cipher)
00433         px_cipher_free(cx->cipher);
00434     px_free(cx);
00435     px_free(buf);
00436     return PXE_NO_CIPHER;
00437 }