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