Age Owner Branch data TLA 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 *
5421 bruce@momjian.us 39 :CBC 71 : mpi_to_bn(PGP_MPI *n)
40 : : {
6756 41 : 71 : BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL);
42 : :
6853 43 [ - + ]: 71 : if (!bn)
6853 bruce@momjian.us 44 :UBC 0 : return NULL;
6853 bruce@momjian.us 45 [ - + ]:CBC 71 : if (BN_num_bits(bn) != n->bits)
46 : : {
6853 bruce@momjian.us 47 :UBC 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 : : }
6853 bruce@momjian.us 52 :CBC 71 : return bn;
53 : : }
54 : :
55 : : static PGP_MPI *
56 : 24 : bn_to_mpi(BIGNUM *bn)
57 : : {
58 : : int res;
59 : : PGP_MPI *n;
60 : :
61 : 24 : res = pgp_mpi_alloc(BN_num_bits(bn), &n);
62 [ - + ]: 24 : if (res < 0)
6853 bruce@momjian.us 63 :UBC 0 : return NULL;
64 : :
6853 bruce@momjian.us 65 [ - + ]:CBC 24 : if (BN_num_bytes(bn) != n->bytes)
66 : : {
6853 bruce@momjian.us 67 :UBC 0 : px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
6756 68 : 0 : BN_num_bytes(bn), n->bytes);
6853 69 : 0 : pgp_mpi_free(n);
70 : 0 : return NULL;
71 : : }
6853 bruce@momjian.us 72 :CBC 24 : BN_bn2bin(bn, n->data);
73 : 24 : 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 : 5 : decide_k_bits(int p_bits)
93 : : {
94 [ + - ]: 5 : if (p_bits <= 5120)
95 : 5 : return p_bits / 10 + 160;
96 : : else
6853 bruce@momjian.us 97 :UBC 0 : return (p_bits / 8 + 200) * 3 / 2;
98 : : }
99 : :
100 : : int
5421 bruce@momjian.us 101 :CBC 5 : pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
102 : : PGP_MPI **c1_p, PGP_MPI **c2_p)
103 : : {
6756 104 : 5 : int res = PXE_PGP_MATH_FAILED;
105 : : int k_bits;
106 : 5 : BIGNUM *m = mpi_to_bn(_m);
107 : 5 : BIGNUM *p = mpi_to_bn(pk->pub.elg.p);
108 : 5 : BIGNUM *g = mpi_to_bn(pk->pub.elg.g);
109 : 5 : BIGNUM *y = mpi_to_bn(pk->pub.elg.y);
110 : 5 : BIGNUM *k = BN_new();
111 : 5 : BIGNUM *yk = BN_new();
112 : 5 : BIGNUM *c1 = BN_new();
113 : 5 : BIGNUM *c2 = BN_new();
114 : 5 : BN_CTX *tmp = BN_CTX_new();
115 : :
6853 116 [ + - + - : 5 : if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
+ - + - +
- + - + -
+ - - + ]
6853 bruce@momjian.us 117 :UBC 0 : goto err;
118 : :
119 : : /*
120 : : * generate k
121 : : */
6853 bruce@momjian.us 122 :CBC 5 : k_bits = decide_k_bits(BN_num_bits(p));
6819 123 [ - + ]: 5 : if (!BN_rand(k, k_bits, 0, 0))
6853 bruce@momjian.us 124 :UBC 0 : goto err;
125 : :
126 : : /*
127 : : * c1 = g^k c2 = m * y^k
128 : : */
6853 bruce@momjian.us 129 [ - + ]:CBC 5 : if (!BN_mod_exp(c1, g, k, p, tmp))
6853 bruce@momjian.us 130 :UBC 0 : goto err;
6853 bruce@momjian.us 131 [ - + ]:CBC 5 : if (!BN_mod_exp(yk, y, k, p, tmp))
6853 bruce@momjian.us 132 :UBC 0 : goto err;
6853 bruce@momjian.us 133 [ - + ]:CBC 5 : if (!BN_mod_mul(c2, m, yk, p, tmp))
6853 bruce@momjian.us 134 :UBC 0 : goto err;
135 : :
136 : : /* result */
6853 bruce@momjian.us 137 :CBC 5 : *c1_p = bn_to_mpi(c1);
138 : 5 : *c2_p = bn_to_mpi(c2);
139 [ - + - + ]: 5 : if (*c1_p && *c2_p)
140 : 5 : res = 0;
6853 bruce@momjian.us 141 :UBC 0 : err:
6756 bruce@momjian.us 142 [ + - ]:CBC 5 : if (tmp)
143 : 5 : BN_CTX_free(tmp);
144 [ + - ]: 5 : if (c2)
145 : 5 : BN_clear_free(c2);
146 [ + - ]: 5 : if (c1)
147 : 5 : BN_clear_free(c1);
148 [ + - ]: 5 : if (yk)
149 : 5 : BN_clear_free(yk);
150 [ + - ]: 5 : if (k)
151 : 5 : BN_clear_free(k);
152 [ + - ]: 5 : if (y)
153 : 5 : BN_clear_free(y);
154 [ + - ]: 5 : if (g)
155 : 5 : BN_clear_free(g);
156 [ + - ]: 5 : if (p)
157 : 5 : BN_clear_free(p);
158 [ + - ]: 5 : if (m)
159 : 5 : BN_clear_free(m);
6853 160 : 5 : return res;
161 : : }
162 : :
163 : : int
5421 164 : 9 : pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
165 : : PGP_MPI **msg_p)
166 : : {
6756 167 : 9 : int res = PXE_PGP_MATH_FAILED;
168 : 9 : BIGNUM *c1 = mpi_to_bn(_c1);
169 : 9 : BIGNUM *c2 = mpi_to_bn(_c2);
170 : 9 : BIGNUM *p = mpi_to_bn(pk->pub.elg.p);
171 : 9 : BIGNUM *x = mpi_to_bn(pk->sec.elg.x);
172 : 9 : BIGNUM *c1x = BN_new();
173 : 9 : BIGNUM *div = BN_new();
174 : 9 : BIGNUM *m = BN_new();
175 : 9 : BN_CTX *tmp = BN_CTX_new();
176 : :
6853 177 [ + - + - : 9 : if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
+ - + - +
- + - + -
- + ]
6853 bruce@momjian.us 178 :UBC 0 : goto err;
179 : :
180 : : /*
181 : : * m = c2 / (c1^x)
182 : : */
6853 bruce@momjian.us 183 [ - + ]:CBC 9 : if (!BN_mod_exp(c1x, c1, x, p, tmp))
6853 bruce@momjian.us 184 :UBC 0 : goto err;
6853 bruce@momjian.us 185 [ - + ]:CBC 9 : if (!BN_mod_inverse(div, c1x, p, tmp))
6853 bruce@momjian.us 186 :UBC 0 : goto err;
6853 bruce@momjian.us 187 [ - + ]:CBC 9 : if (!BN_mod_mul(m, c2, div, p, tmp))
6853 bruce@momjian.us 188 :UBC 0 : goto err;
189 : :
190 : : /* result */
6853 bruce@momjian.us 191 :CBC 9 : *msg_p = bn_to_mpi(m);
192 [ - + ]: 9 : if (*msg_p)
193 : 9 : res = 0;
6853 bruce@momjian.us 194 :UBC 0 : err:
6756 bruce@momjian.us 195 [ + - ]:CBC 9 : if (tmp)
196 : 9 : BN_CTX_free(tmp);
197 [ + - ]: 9 : if (m)
198 : 9 : BN_clear_free(m);
199 [ + - ]: 9 : if (div)
200 : 9 : BN_clear_free(div);
201 [ + - ]: 9 : if (c1x)
202 : 9 : BN_clear_free(c1x);
203 [ + - ]: 9 : if (x)
204 : 9 : BN_clear_free(x);
205 [ + - ]: 9 : if (p)
206 : 9 : BN_clear_free(p);
207 [ + - ]: 9 : if (c2)
208 : 9 : BN_clear_free(c2);
209 [ + - ]: 9 : if (c1)
210 : 9 : BN_clear_free(c1);
6853 211 : 9 : return res;
212 : : }
213 : :
214 : : int
5421 215 : 1 : pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
216 : : {
6756 217 : 1 : int res = PXE_PGP_MATH_FAILED;
218 : 1 : BIGNUM *m = mpi_to_bn(_m);
219 : 1 : BIGNUM *e = mpi_to_bn(pk->pub.rsa.e);
220 : 1 : BIGNUM *n = mpi_to_bn(pk->pub.rsa.n);
221 : 1 : BIGNUM *c = BN_new();
222 : 1 : BN_CTX *tmp = BN_CTX_new();
223 : :
6819 224 [ + - + - : 1 : if (!m || !e || !n || !c || !tmp)
+ - + - -
+ ]
6819 bruce@momjian.us 225 :UBC 0 : goto err;
226 : :
227 : : /*
228 : : * c = m ^ e
229 : : */
6819 bruce@momjian.us 230 [ - + ]:CBC 1 : if (!BN_mod_exp(c, m, e, n, tmp))
6819 bruce@momjian.us 231 :UBC 0 : goto err;
232 : :
6819 bruce@momjian.us 233 :CBC 1 : *c_p = bn_to_mpi(c);
234 [ - + ]: 1 : if (*c_p)
235 : 1 : res = 0;
6819 bruce@momjian.us 236 :UBC 0 : err:
6756 bruce@momjian.us 237 [ + - ]:CBC 1 : if (tmp)
238 : 1 : BN_CTX_free(tmp);
239 [ + - ]: 1 : if (c)
240 : 1 : BN_clear_free(c);
241 [ + - ]: 1 : if (n)
242 : 1 : BN_clear_free(n);
243 [ + - ]: 1 : if (e)
244 : 1 : BN_clear_free(e);
245 [ + - ]: 1 : if (m)
246 : 1 : BN_clear_free(m);
6819 247 : 1 : return res;
248 : : }
249 : :
250 : : int
5421 251 : 4 : pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
252 : : {
6756 253 : 4 : int res = PXE_PGP_MATH_FAILED;
254 : 4 : BIGNUM *c = mpi_to_bn(_c);
255 : 4 : BIGNUM *d = mpi_to_bn(pk->sec.rsa.d);
256 : 4 : BIGNUM *n = mpi_to_bn(pk->pub.rsa.n);
257 : 4 : BIGNUM *m = BN_new();
258 : 4 : BN_CTX *tmp = BN_CTX_new();
259 : :
6819 260 [ + - + - : 4 : if (!m || !d || !n || !c || !tmp)
+ - + - -
+ ]
6819 bruce@momjian.us 261 :UBC 0 : goto err;
262 : :
263 : : /*
264 : : * m = c ^ d
265 : : */
6819 bruce@momjian.us 266 [ - + ]:CBC 4 : if (!BN_mod_exp(m, c, d, n, tmp))
6819 bruce@momjian.us 267 :UBC 0 : goto err;
268 : :
6819 bruce@momjian.us 269 :CBC 4 : *m_p = bn_to_mpi(m);
270 [ - + ]: 4 : if (*m_p)
271 : 4 : res = 0;
6819 bruce@momjian.us 272 :UBC 0 : err:
6756 bruce@momjian.us 273 [ + - ]:CBC 4 : if (tmp)
274 : 4 : BN_CTX_free(tmp);
275 [ + - ]: 4 : if (m)
276 : 4 : BN_clear_free(m);
277 [ + - ]: 4 : if (n)
278 : 4 : BN_clear_free(n);
279 [ + - ]: 4 : if (d)
280 : 4 : BN_clear_free(d);
281 [ + - ]: 4 : if (c)
282 : 4 : BN_clear_free(c);
6819 283 : 4 : return res;
284 : : }
|