OSDN Git Service

8.4 pgindent run, with new combined Linux/FreeBSD/MinGW typedef list
[pg-rex/syncrep.git] / contrib / pgcrypto / pgp-mpi-openssl.c
1 /*
2  * pgp-mpi-openssl.c
3  *        OpenPGP MPI functions using OpenSSL BIGNUM code.
4  *
5  * Copyright (c) 2005 Marko Kreen
6  * All rights reserved.
7  *
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.
16  *
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.
28  *
29  * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-openssl.c,v 1.5 2009/06/11 14:48:52 momjian Exp $
30  */
31 #include "postgres.h"
32
33 #include <openssl/bn.h>
34
35 #include "px.h"
36 #include "mbuf.h"
37 #include "pgp.h"
38
39 static BIGNUM *
40 mpi_to_bn(PGP_MPI *n)
41 {
42         BIGNUM     *bn = BN_bin2bn(n->data, n->bytes, NULL);
43
44         if (!bn)
45                 return NULL;
46         if (BN_num_bits(bn) != n->bits)
47         {
48                 px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
49                                  n->bits, BN_num_bits(bn));
50                 BN_clear_free(bn);
51                 return NULL;
52         }
53         return bn;
54 }
55
56 static PGP_MPI *
57 bn_to_mpi(BIGNUM *bn)
58 {
59         int                     res;
60         PGP_MPI    *n;
61
62         res = pgp_mpi_alloc(BN_num_bits(bn), &n);
63         if (res < 0)
64                 return NULL;
65
66         if (BN_num_bytes(bn) != n->bytes)
67         {
68                 px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
69                                  BN_num_bytes(bn), n->bytes);
70                 pgp_mpi_free(n);
71                 return NULL;
72         }
73         BN_bn2bin(bn, n->data);
74         return n;
75 }
76
77 /*
78  * Decide the number of bits in the random componont k
79  *
80  * It should be in the same range as p for signing (which
81  * is deprecated), but can be much smaller for encrypting.
82  *
83  * Until I research it further, I just mimic gpg behaviour.
84  * It has a special mapping table, for values <= 5120,
85  * above that it uses 'arbitrary high number'.  Following
86  * algorihm hovers 10-70 bits above gpg values.  And for
87  * larger p, it uses gpg's algorihm.
88  *
89  * The point is - if k gets large, encryption will be
90  * really slow.  It does not matter for decryption.
91  */
92 static int
93 decide_k_bits(int p_bits)
94 {
95         if (p_bits <= 5120)
96                 return p_bits / 10 + 160;
97         else
98                 return (p_bits / 8 + 200) * 3 / 2;
99 }
100
101 int
102 pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
103                                         PGP_MPI **c1_p, PGP_MPI **c2_p)
104 {
105         int                     res = PXE_PGP_MATH_FAILED;
106         int                     k_bits;
107         BIGNUM     *m = mpi_to_bn(_m);
108         BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
109         BIGNUM     *g = mpi_to_bn(pk->pub.elg.g);
110         BIGNUM     *y = mpi_to_bn(pk->pub.elg.y);
111         BIGNUM     *k = BN_new();
112         BIGNUM     *yk = BN_new();
113         BIGNUM     *c1 = BN_new();
114         BIGNUM     *c2 = BN_new();
115         BN_CTX     *tmp = BN_CTX_new();
116
117         if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
118                 goto err;
119
120         /*
121          * generate k
122          */
123         k_bits = decide_k_bits(BN_num_bits(p));
124         if (!BN_rand(k, k_bits, 0, 0))
125                 goto err;
126
127         /*
128          * c1 = g^k c2 = m * y^k
129          */
130         if (!BN_mod_exp(c1, g, k, p, tmp))
131                 goto err;
132         if (!BN_mod_exp(yk, y, k, p, tmp))
133                 goto err;
134         if (!BN_mod_mul(c2, m, yk, p, tmp))
135                 goto err;
136
137         /* result */
138         *c1_p = bn_to_mpi(c1);
139         *c2_p = bn_to_mpi(c2);
140         if (*c1_p && *c2_p)
141                 res = 0;
142 err:
143         if (tmp)
144                 BN_CTX_free(tmp);
145         if (c2)
146                 BN_clear_free(c2);
147         if (c1)
148                 BN_clear_free(c1);
149         if (yk)
150                 BN_clear_free(yk);
151         if (k)
152                 BN_clear_free(k);
153         if (y)
154                 BN_clear_free(y);
155         if (g)
156                 BN_clear_free(g);
157         if (p)
158                 BN_clear_free(p);
159         if (m)
160                 BN_clear_free(m);
161         return res;
162 }
163
164 int
165 pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
166                                         PGP_MPI **msg_p)
167 {
168         int                     res = PXE_PGP_MATH_FAILED;
169         BIGNUM     *c1 = mpi_to_bn(_c1);
170         BIGNUM     *c2 = mpi_to_bn(_c2);
171         BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
172         BIGNUM     *x = mpi_to_bn(pk->sec.elg.x);
173         BIGNUM     *c1x = BN_new();
174         BIGNUM     *div = BN_new();
175         BIGNUM     *m = BN_new();
176         BN_CTX     *tmp = BN_CTX_new();
177
178         if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
179                 goto err;
180
181         /*
182          * m = c2 / (c1^x)
183          */
184         if (!BN_mod_exp(c1x, c1, x, p, tmp))
185                 goto err;
186         if (!BN_mod_inverse(div, c1x, p, tmp))
187                 goto err;
188         if (!BN_mod_mul(m, c2, div, p, tmp))
189                 goto err;
190
191         /* result */
192         *msg_p = bn_to_mpi(m);
193         if (*msg_p)
194                 res = 0;
195 err:
196         if (tmp)
197                 BN_CTX_free(tmp);
198         if (m)
199                 BN_clear_free(m);
200         if (div)
201                 BN_clear_free(div);
202         if (c1x)
203                 BN_clear_free(c1x);
204         if (x)
205                 BN_clear_free(x);
206         if (p)
207                 BN_clear_free(p);
208         if (c2)
209                 BN_clear_free(c2);
210         if (c1)
211                 BN_clear_free(c1);
212         return res;
213 }
214
215 int
216 pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
217 {
218         int                     res = PXE_PGP_MATH_FAILED;
219         BIGNUM     *m = mpi_to_bn(_m);
220         BIGNUM     *e = mpi_to_bn(pk->pub.rsa.e);
221         BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
222         BIGNUM     *c = BN_new();
223         BN_CTX     *tmp = BN_CTX_new();
224
225         if (!m || !e || !n || !c || !tmp)
226                 goto err;
227
228         /*
229          * c = m ^ e
230          */
231         if (!BN_mod_exp(c, m, e, n, tmp))
232                 goto err;
233
234         *c_p = bn_to_mpi(c);
235         if (*c_p)
236                 res = 0;
237 err:
238         if (tmp)
239                 BN_CTX_free(tmp);
240         if (c)
241                 BN_clear_free(c);
242         if (n)
243                 BN_clear_free(n);
244         if (e)
245                 BN_clear_free(e);
246         if (m)
247                 BN_clear_free(m);
248         return res;
249 }
250
251 int
252 pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
253 {
254         int                     res = PXE_PGP_MATH_FAILED;
255         BIGNUM     *c = mpi_to_bn(_c);
256         BIGNUM     *d = mpi_to_bn(pk->sec.rsa.d);
257         BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
258         BIGNUM     *m = BN_new();
259         BN_CTX     *tmp = BN_CTX_new();
260
261         if (!m || !d || !n || !c || !tmp)
262                 goto err;
263
264         /*
265          * m = c ^ d
266          */
267         if (!BN_mod_exp(m, c, d, n, tmp))
268                 goto err;
269
270         *m_p = bn_to_mpi(m);
271         if (*m_p)
272                 res = 0;
273 err:
274         if (tmp)
275                 BN_CTX_free(tmp);
276         if (m)
277                 BN_clear_free(m);
278         if (n)
279                 BN_clear_free(n);
280         if (d)
281                 BN_clear_free(d);
282         if (c)
283                 BN_clear_free(c);
284         return res;
285 }