Header And Logo

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

pgp-mpi-openssl.c

Go to the documentation of this file.
00001 /*
00002  * pgp-mpi-openssl.c
00003  *    OpenPGP MPI functions using OpenSSL BIGNUM code.
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-mpi-openssl.c
00030  */
00031 #include "postgres.h"
00032 
00033 #include <openssl/bn.h>
00034 
00035 #include "px.h"
00036 #include "mbuf.h"
00037 #include "pgp.h"
00038 
00039 static BIGNUM *
00040 mpi_to_bn(PGP_MPI *n)
00041 {
00042     BIGNUM     *bn = BN_bin2bn(n->data, n->bytes, NULL);
00043 
00044     if (!bn)
00045         return NULL;
00046     if (BN_num_bits(bn) != n->bits)
00047     {
00048         px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
00049                  n->bits, BN_num_bits(bn));
00050         BN_clear_free(bn);
00051         return NULL;
00052     }
00053     return bn;
00054 }
00055 
00056 static PGP_MPI *
00057 bn_to_mpi(BIGNUM *bn)
00058 {
00059     int         res;
00060     PGP_MPI    *n;
00061 
00062     res = pgp_mpi_alloc(BN_num_bits(bn), &n);
00063     if (res < 0)
00064         return NULL;
00065 
00066     if (BN_num_bytes(bn) != n->bytes)
00067     {
00068         px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
00069                  BN_num_bytes(bn), n->bytes);
00070         pgp_mpi_free(n);
00071         return NULL;
00072     }
00073     BN_bn2bin(bn, n->data);
00074     return n;
00075 }
00076 
00077 /*
00078  * Decide the number of bits in the random componont k
00079  *
00080  * It should be in the same range as p for signing (which
00081  * is deprecated), but can be much smaller for encrypting.
00082  *
00083  * Until I research it further, I just mimic gpg behaviour.
00084  * It has a special mapping table, for values <= 5120,
00085  * above that it uses 'arbitrary high number'.  Following
00086  * algorihm hovers 10-70 bits above gpg values.  And for
00087  * larger p, it uses gpg's algorihm.
00088  *
00089  * The point is - if k gets large, encryption will be
00090  * really slow.  It does not matter for decryption.
00091  */
00092 static int
00093 decide_k_bits(int p_bits)
00094 {
00095     if (p_bits <= 5120)
00096         return p_bits / 10 + 160;
00097     else
00098         return (p_bits / 8 + 200) * 3 / 2;
00099 }
00100 
00101 int
00102 pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
00103                     PGP_MPI **c1_p, PGP_MPI **c2_p)
00104 {
00105     int         res = PXE_PGP_MATH_FAILED;
00106     int         k_bits;
00107     BIGNUM     *m = mpi_to_bn(_m);
00108     BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
00109     BIGNUM     *g = mpi_to_bn(pk->pub.elg.g);
00110     BIGNUM     *y = mpi_to_bn(pk->pub.elg.y);
00111     BIGNUM     *k = BN_new();
00112     BIGNUM     *yk = BN_new();
00113     BIGNUM     *c1 = BN_new();
00114     BIGNUM     *c2 = BN_new();
00115     BN_CTX     *tmp = BN_CTX_new();
00116 
00117     if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
00118         goto err;
00119 
00120     /*
00121      * generate k
00122      */
00123     k_bits = decide_k_bits(BN_num_bits(p));
00124     if (!BN_rand(k, k_bits, 0, 0))
00125         goto err;
00126 
00127     /*
00128      * c1 = g^k c2 = m * y^k
00129      */
00130     if (!BN_mod_exp(c1, g, k, p, tmp))
00131         goto err;
00132     if (!BN_mod_exp(yk, y, k, p, tmp))
00133         goto err;
00134     if (!BN_mod_mul(c2, m, yk, p, tmp))
00135         goto err;
00136 
00137     /* result */
00138     *c1_p = bn_to_mpi(c1);
00139     *c2_p = bn_to_mpi(c2);
00140     if (*c1_p && *c2_p)
00141         res = 0;
00142 err:
00143     if (tmp)
00144         BN_CTX_free(tmp);
00145     if (c2)
00146         BN_clear_free(c2);
00147     if (c1)
00148         BN_clear_free(c1);
00149     if (yk)
00150         BN_clear_free(yk);
00151     if (k)
00152         BN_clear_free(k);
00153     if (y)
00154         BN_clear_free(y);
00155     if (g)
00156         BN_clear_free(g);
00157     if (p)
00158         BN_clear_free(p);
00159     if (m)
00160         BN_clear_free(m);
00161     return res;
00162 }
00163 
00164 int
00165 pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
00166                     PGP_MPI **msg_p)
00167 {
00168     int         res = PXE_PGP_MATH_FAILED;
00169     BIGNUM     *c1 = mpi_to_bn(_c1);
00170     BIGNUM     *c2 = mpi_to_bn(_c2);
00171     BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
00172     BIGNUM     *x = mpi_to_bn(pk->sec.elg.x);
00173     BIGNUM     *c1x = BN_new();
00174     BIGNUM     *div = BN_new();
00175     BIGNUM     *m = BN_new();
00176     BN_CTX     *tmp = BN_CTX_new();
00177 
00178     if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
00179         goto err;
00180 
00181     /*
00182      * m = c2 / (c1^x)
00183      */
00184     if (!BN_mod_exp(c1x, c1, x, p, tmp))
00185         goto err;
00186     if (!BN_mod_inverse(div, c1x, p, tmp))
00187         goto err;
00188     if (!BN_mod_mul(m, c2, div, p, tmp))
00189         goto err;
00190 
00191     /* result */
00192     *msg_p = bn_to_mpi(m);
00193     if (*msg_p)
00194         res = 0;
00195 err:
00196     if (tmp)
00197         BN_CTX_free(tmp);
00198     if (m)
00199         BN_clear_free(m);
00200     if (div)
00201         BN_clear_free(div);
00202     if (c1x)
00203         BN_clear_free(c1x);
00204     if (x)
00205         BN_clear_free(x);
00206     if (p)
00207         BN_clear_free(p);
00208     if (c2)
00209         BN_clear_free(c2);
00210     if (c1)
00211         BN_clear_free(c1);
00212     return res;
00213 }
00214 
00215 int
00216 pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
00217 {
00218     int         res = PXE_PGP_MATH_FAILED;
00219     BIGNUM     *m = mpi_to_bn(_m);
00220     BIGNUM     *e = mpi_to_bn(pk->pub.rsa.e);
00221     BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
00222     BIGNUM     *c = BN_new();
00223     BN_CTX     *tmp = BN_CTX_new();
00224 
00225     if (!m || !e || !n || !c || !tmp)
00226         goto err;
00227 
00228     /*
00229      * c = m ^ e
00230      */
00231     if (!BN_mod_exp(c, m, e, n, tmp))
00232         goto err;
00233 
00234     *c_p = bn_to_mpi(c);
00235     if (*c_p)
00236         res = 0;
00237 err:
00238     if (tmp)
00239         BN_CTX_free(tmp);
00240     if (c)
00241         BN_clear_free(c);
00242     if (n)
00243         BN_clear_free(n);
00244     if (e)
00245         BN_clear_free(e);
00246     if (m)
00247         BN_clear_free(m);
00248     return res;
00249 }
00250 
00251 int
00252 pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
00253 {
00254     int         res = PXE_PGP_MATH_FAILED;
00255     BIGNUM     *c = mpi_to_bn(_c);
00256     BIGNUM     *d = mpi_to_bn(pk->sec.rsa.d);
00257     BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
00258     BIGNUM     *m = BN_new();
00259     BN_CTX     *tmp = BN_CTX_new();
00260 
00261     if (!m || !d || !n || !c || !tmp)
00262         goto err;
00263 
00264     /*
00265      * m = c ^ d
00266      */
00267     if (!BN_mod_exp(m, c, d, n, tmp))
00268         goto err;
00269 
00270     *m_p = bn_to_mpi(m);
00271     if (*m_p)
00272         res = 0;
00273 err:
00274     if (tmp)
00275         BN_CTX_free(tmp);
00276     if (m)
00277         BN_clear_free(m);
00278     if (n)
00279         BN_clear_free(n);
00280     if (d)
00281         BN_clear_free(d);
00282     if (c)
00283         BN_clear_free(c);
00284     return res;
00285 }