Header And Logo

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

pgp-s2k.c

Go to the documentation of this file.
00001 /*
00002  * pgp-s2k.c
00003  *    OpenPGP string2key functions.
00004  *
00005  * Copyright (c) 2005 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/pgp-s2k.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "px.h"
00035 #include "mbuf.h"
00036 #include "pgp.h"
00037 
00038 static int
00039 calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
00040                 unsigned key_len)
00041 {
00042     unsigned    md_rlen;
00043     uint8       buf[PGP_MAX_DIGEST];
00044     unsigned    preload;
00045     unsigned    remain;
00046     uint8      *dst = s2k->key;
00047 
00048     md_rlen = px_md_result_size(md);
00049 
00050     remain = s2k->key_len;
00051     preload = 0;
00052     while (remain > 0)
00053     {
00054         px_md_reset(md);
00055 
00056         if (preload)
00057         {
00058             memset(buf, 0, preload);
00059             px_md_update(md, buf, preload);
00060         }
00061         preload++;
00062 
00063         px_md_update(md, key, key_len);
00064         px_md_finish(md, buf);
00065 
00066         if (remain > md_rlen)
00067         {
00068             memcpy(dst, buf, md_rlen);
00069             dst += md_rlen;
00070             remain -= md_rlen;
00071         }
00072         else
00073         {
00074             memcpy(dst, buf, remain);
00075             remain = 0;
00076         }
00077     }
00078     return 0;
00079 }
00080 
00081 static int
00082 calc_s2k_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len)
00083 {
00084     unsigned    md_rlen;
00085     uint8       buf[PGP_MAX_DIGEST];
00086     unsigned    preload = 0;
00087     uint8      *dst;
00088     unsigned    remain;
00089 
00090     md_rlen = px_md_result_size(md);
00091 
00092     dst = s2k->key;
00093     remain = s2k->key_len;
00094     while (remain > 0)
00095     {
00096         px_md_reset(md);
00097 
00098         if (preload > 0)
00099         {
00100             memset(buf, 0, preload);
00101             px_md_update(md, buf, preload);
00102         }
00103         preload++;
00104 
00105         px_md_update(md, s2k->salt, PGP_S2K_SALT);
00106         px_md_update(md, key, key_len);
00107         px_md_finish(md, buf);
00108 
00109         if (remain > md_rlen)
00110         {
00111             memcpy(dst, buf, md_rlen);
00112             remain -= md_rlen;
00113             dst += md_rlen;
00114         }
00115         else
00116         {
00117             memcpy(dst, buf, remain);
00118             remain = 0;
00119         }
00120     }
00121     return 0;
00122 }
00123 
00124 static int
00125 calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
00126                      unsigned key_len)
00127 {
00128     unsigned    md_rlen;
00129     uint8       buf[PGP_MAX_DIGEST];
00130     uint8      *dst;
00131     unsigned    preload = 0;
00132     unsigned    remain,
00133                 c,
00134                 cval,
00135                 curcnt,
00136                 count;
00137 
00138     cval = s2k->iter;
00139     count = ((unsigned) 16 + (cval & 15)) << ((cval >> 4) + 6);
00140 
00141     md_rlen = px_md_result_size(md);
00142 
00143     remain = s2k->key_len;
00144     dst = s2k->key;
00145     while (remain > 0)
00146     {
00147         px_md_reset(md);
00148 
00149         if (preload)
00150         {
00151             memset(buf, 0, preload);
00152             px_md_update(md, buf, preload);
00153         }
00154         preload++;
00155 
00156         px_md_update(md, s2k->salt, PGP_S2K_SALT);
00157         px_md_update(md, key, key_len);
00158         curcnt = PGP_S2K_SALT + key_len;
00159 
00160         while (curcnt < count)
00161         {
00162             if (curcnt + PGP_S2K_SALT < count)
00163                 c = PGP_S2K_SALT;
00164             else
00165                 c = count - curcnt;
00166             px_md_update(md, s2k->salt, c);
00167             curcnt += c;
00168 
00169             if (curcnt + key_len < count)
00170                 c = key_len;
00171             else if (curcnt < count)
00172                 c = count - curcnt;
00173             else
00174                 break;
00175             px_md_update(md, key, c);
00176             curcnt += c;
00177         }
00178         px_md_finish(md, buf);
00179 
00180         if (remain > md_rlen)
00181         {
00182             memcpy(dst, buf, md_rlen);
00183             remain -= md_rlen;
00184             dst += md_rlen;
00185         }
00186         else
00187         {
00188             memcpy(dst, buf, remain);
00189             remain = 0;
00190         }
00191     }
00192     return 0;
00193 }
00194 
00195 /*
00196  * Decide S2K_ISALTED iteration count
00197  *
00198  * Too small: weak
00199  * Too big: slow
00200  * gpg defaults to 96 => 65536 iters
00201  * let it float a bit: 96 + 32 => 262144 iters
00202  */
00203 static int
00204 decide_count(unsigned rand_byte)
00205 {
00206     return 96 + (rand_byte & 0x1F);
00207 }
00208 
00209 int
00210 pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo)
00211 {
00212     int         res = 0;
00213     uint8       tmp;
00214 
00215     s2k->mode = mode;
00216     s2k->digest_algo = digest_algo;
00217 
00218     switch (s2k->mode)
00219     {
00220         case 0:
00221             break;
00222         case 1:
00223             res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
00224             break;
00225         case 3:
00226             res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT);
00227             if (res < 0)
00228                 break;
00229             res = px_get_pseudo_random_bytes(&tmp, 1);
00230             if (res < 0)
00231                 break;
00232             s2k->iter = decide_count(tmp);
00233             break;
00234         default:
00235             res = PXE_PGP_BAD_S2K_MODE;
00236     }
00237     return res;
00238 }
00239 
00240 int
00241 pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
00242 {
00243     int         res = 0;
00244 
00245     GETBYTE(src, s2k->mode);
00246     GETBYTE(src, s2k->digest_algo);
00247     switch (s2k->mode)
00248     {
00249         case 0:
00250             break;
00251         case 1:
00252             res = pullf_read_fixed(src, 8, s2k->salt);
00253             break;
00254         case 3:
00255             res = pullf_read_fixed(src, 8, s2k->salt);
00256             if (res < 0)
00257                 break;
00258             GETBYTE(src, s2k->iter);
00259             break;
00260         default:
00261             res = PXE_PGP_BAD_S2K_MODE;
00262     }
00263     return res;
00264 }
00265 
00266 int
00267 pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
00268 {
00269     int         res;
00270     PX_MD      *md;
00271 
00272     s2k->key_len = pgp_get_cipher_key_size(cipher);
00273     if (s2k->key_len <= 0)
00274         return PXE_PGP_UNSUPPORTED_CIPHER;
00275 
00276     res = pgp_load_digest(s2k->digest_algo, &md);
00277     if (res < 0)
00278         return res;
00279 
00280     switch (s2k->mode)
00281     {
00282         case 0:
00283             res = calc_s2k_simple(s2k, md, key, key_len);
00284             break;
00285         case 1:
00286             res = calc_s2k_salted(s2k, md, key, key_len);
00287             break;
00288         case 3:
00289             res = calc_s2k_iter_salted(s2k, md, key, key_len);
00290             break;
00291         default:
00292             res = PXE_PGP_BAD_S2K_MODE;
00293     }
00294     px_md_free(md);
00295     return res;
00296 }