• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@cryptsoft.com).
6  * The implementation was written so as to conform with Netscapes SSL.
7  *
8  * This library is free for commercial and non-commercial use as long as
9  * the following conditions are aheared to.  The following conditions
10  * apply to all code found in this distribution, be it the RC4, RSA,
11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12  * included with this distribution is covered by the same copyright terms
13  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14  *
15  * Copyright remains Eric Young's, and as such any Copyright notices in
16  * the code are not to be removed.
17  * If this package is used in a product, Eric Young should be given attribution
18  * as the author of the parts of the library used.
19  * This can be in the form of a textual message at program startup or
20  * in documentation (online or textual) provided with the package.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  * 1. Redistributions of source code must retain the copyright
26  *    notice, this list of conditions and the following disclaimer.
27  * 2. Redistributions in binary form must reproduce the above copyright
28  *    notice, this list of conditions and the following disclaimer in the
29  *    documentation and/or other materials provided with the distribution.
30  * 3. All advertising materials mentioning features or use of this software
31  *    must display the following acknowledgement:
32  *    "This product includes cryptographic software written by
33  *     Eric Young (eay@cryptsoft.com)"
34  *    The word 'cryptographic' can be left out if the rouines from the library
35  *    being used are not cryptographic related :-).
36  * 4. If you include any Windows specific code (or a derivative thereof) from
37  *    the apps directory (application code) you must include an acknowledgement:
38  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  *
52  * The licence and distribution terms for any publically available version or
53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
54  * copied and put under another distribution licence
55  * [including the GNU Public Licence.]
56  */
57 /* ====================================================================
58  * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
59  *
60  * Redistribution and use in source and binary forms, with or without
61  * modification, are permitted provided that the following conditions
62  * are met:
63  *
64  * 1. Redistributions of source code must retain the above copyright
65  *    notice, this list of conditions and the following disclaimer.
66  *
67  * 2. Redistributions in binary form must reproduce the above copyright
68  *    notice, this list of conditions and the following disclaimer in
69  *    the documentation and/or other materials provided with the
70  *    distribution.
71  *
72  * 3. All advertising materials mentioning features or use of this
73  *    software must display the following acknowledgment:
74  *    "This product includes software developed by the OpenSSL Project
75  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
76  *
77  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
78  *    endorse or promote products derived from this software without
79  *    prior written permission. For written permission, please contact
80  *    openssl-core@openssl.org.
81  *
82  * 5. Products derived from this software may not be called "OpenSSL"
83  *    nor may "OpenSSL" appear in their names without prior written
84  *    permission of the OpenSSL Project.
85  *
86  * 6. Redistributions of any form whatsoever must retain the following
87  *    acknowledgment:
88  *    "This product includes software developed by the OpenSSL Project
89  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
90  *
91  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
92  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
94  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
95  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
96  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
97  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
98  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
100  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
101  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
102  * OF THE POSSIBILITY OF SUCH DAMAGE.
103  * ====================================================================
104  *
105  * This product includes cryptographic software written by Eric Young
106  * (eay@cryptsoft.com).  This product includes software written by Tim
107  * Hudson (tjh@cryptsoft.com). */
108 
109 #include <openssl/bn.h>
110 
111 #include <string.h>
112 
113 #include <openssl/err.h>
114 #include <openssl/mem.h>
115 #include <openssl/thread.h>
116 
117 #include "internal.h"
118 #include "../internal.h"
119 
120 
121 #if !defined(OPENSSL_NO_ASM) &&                         \
122     (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
123      defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
124 #define OPENSSL_BN_ASM_MONT
125 #endif
126 
BN_MONT_CTX_new(void)127 BN_MONT_CTX *BN_MONT_CTX_new(void) {
128   BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX));
129 
130   if (ret == NULL) {
131     return NULL;
132   }
133 
134   memset(ret, 0, sizeof(BN_MONT_CTX));
135   BN_init(&ret->RR);
136   BN_init(&ret->N);
137 
138   return ret;
139 }
140 
BN_MONT_CTX_free(BN_MONT_CTX * mont)141 void BN_MONT_CTX_free(BN_MONT_CTX *mont) {
142   if (mont == NULL) {
143     return;
144   }
145 
146   BN_free(&mont->RR);
147   BN_free(&mont->N);
148   OPENSSL_free(mont);
149 }
150 
BN_MONT_CTX_copy(BN_MONT_CTX * to,const BN_MONT_CTX * from)151 BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, const BN_MONT_CTX *from) {
152   if (to == from) {
153     return to;
154   }
155 
156   if (!BN_copy(&to->RR, &from->RR) ||
157       !BN_copy(&to->N, &from->N)) {
158     return NULL;
159   }
160   to->n0[0] = from->n0[0];
161   to->n0[1] = from->n0[1];
162   return to;
163 }
164 
BN_MONT_CTX_set(BN_MONT_CTX * mont,const BIGNUM * mod,BN_CTX * ctx)165 int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) {
166   int ret = 0;
167   BIGNUM *Ri, *R;
168   BIGNUM tmod;
169   BN_ULONG buf[2];
170 
171   if (BN_is_zero(mod)) {
172     OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
173     return 0;
174   }
175 
176   BN_CTX_start(ctx);
177   Ri = BN_CTX_get(ctx);
178   if (Ri == NULL) {
179     goto err;
180   }
181   R = &mont->RR; /* grab RR as a temp */
182   if (!BN_copy(&mont->N, mod)) {
183     goto err; /* Set N */
184   }
185   mont->N.neg = 0;
186 
187   BN_init(&tmod);
188   tmod.d = buf;
189   tmod.dmax = 2;
190   tmod.neg = 0;
191 
192 #if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32)
193   /* Only certain BN_BITS2<=32 platforms actually make use of
194    * n0[1], and we could use the #else case (with a shorter R
195    * value) for the others.  However, currently only the assembler
196    * files do know which is which. */
197 
198   BN_zero(R);
199   if (!BN_set_bit(R, 2 * BN_BITS2)) {
200     goto err;
201   }
202 
203   tmod.top = 0;
204   if ((buf[0] = mod->d[0])) {
205     tmod.top = 1;
206   }
207   if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) {
208     tmod.top = 2;
209   }
210 
211   if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
212     goto err;
213   }
214   if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) {
215     goto err; /* R*Ri */
216   }
217   if (!BN_is_zero(Ri)) {
218     if (!BN_sub_word(Ri, 1)) {
219       goto err;
220     }
221   } else {
222     /* if N mod word size == 1 */
223     if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) {
224       goto err;
225     }
226     /* Ri-- (mod double word size) */
227     Ri->neg = 0;
228     Ri->d[0] = BN_MASK2;
229     Ri->d[1] = BN_MASK2;
230     Ri->top = 2;
231   }
232 
233   if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
234     goto err;
235   }
236   /* Ni = (R*Ri-1)/N,
237    * keep only couple of least significant words: */
238   mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
239   mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0;
240 #else
241   BN_zero(R);
242   if (!BN_set_bit(R, BN_BITS2)) {
243     goto err; /* R */
244   }
245 
246   buf[0] = mod->d[0]; /* tmod = N mod word size */
247   buf[1] = 0;
248   tmod.top = buf[0] != 0 ? 1 : 0;
249   /* Ri = R^-1 mod N*/
250   if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) {
251     goto err;
252   }
253   if (!BN_lshift(Ri, Ri, BN_BITS2)) {
254     goto err; /* R*Ri */
255   }
256   if (!BN_is_zero(Ri)) {
257     if (!BN_sub_word(Ri, 1)) {
258       goto err;
259     }
260   } else {
261     /* if N mod word size == 1 */
262     if (!BN_set_word(Ri, BN_MASK2)) {
263       goto err; /* Ri-- (mod word size) */
264     }
265   }
266   if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) {
267     goto err;
268   }
269   /* Ni = (R*Ri-1)/N,
270    * keep only least significant word: */
271   mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0;
272   mont->n0[1] = 0;
273 #endif
274 
275   /* RR = (2^ri)^2 == 2^(ri*2) == 1 << (ri*2), which has its (ri*2)th bit set. */
276   int ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2;
277   BN_zero(&(mont->RR));
278   if (!BN_set_bit(&(mont->RR), ri * 2)) {
279     goto err;
280   }
281   if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) {
282     goto err;
283   }
284 
285   ret = 1;
286 
287 err:
288   BN_CTX_end(ctx);
289   return ret;
290 }
291 
BN_MONT_CTX_set_locked(BN_MONT_CTX ** pmont,CRYPTO_MUTEX * lock,const BIGNUM * mod,BN_CTX * bn_ctx)292 BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock,
293                                     const BIGNUM *mod, BN_CTX *bn_ctx) {
294   CRYPTO_MUTEX_lock_read(lock);
295   BN_MONT_CTX *ctx = *pmont;
296   CRYPTO_MUTEX_unlock(lock);
297 
298   if (ctx) {
299     return ctx;
300   }
301 
302   CRYPTO_MUTEX_lock_write(lock);
303   ctx = *pmont;
304   if (ctx) {
305     goto out;
306   }
307 
308   ctx = BN_MONT_CTX_new();
309   if (ctx == NULL) {
310     goto out;
311   }
312   if (!BN_MONT_CTX_set(ctx, mod, bn_ctx)) {
313     BN_MONT_CTX_free(ctx);
314     ctx = NULL;
315     goto out;
316   }
317   *pmont = ctx;
318 
319 out:
320   CRYPTO_MUTEX_unlock(lock);
321   return ctx;
322 }
323 
BN_to_montgomery(BIGNUM * ret,const BIGNUM * a,const BN_MONT_CTX * mont,BN_CTX * ctx)324 int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
325                      BN_CTX *ctx) {
326   return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx);
327 }
328 
329 #if 0
330 static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r,
331                                    const BN_MONT_CTX *mont) {
332   const BIGNUM *n;
333   BN_ULONG *ap, *np, *rp, n0, v, carry;
334   int nl, max, i;
335 
336   n = &mont->N;
337   nl = n->top;
338   if (nl == 0) {
339     ret->top = 0;
340     return 1;
341   }
342 
343   max = (2 * nl); /* carry is stored separately */
344   if (bn_wexpand(r, max) == NULL) {
345     return 0;
346   }
347 
348   r->neg ^= n->neg;
349   np = n->d;
350   rp = r->d;
351 
352   /* clear the top words of T */
353   if (max > r->top) {
354     memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG));
355   }
356 
357   r->top = max;
358   n0 = mont->n0[0];
359 
360   for (carry = 0, i = 0; i < nl; i++, rp++) {
361     v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2);
362     v = (v + carry + rp[nl]) & BN_MASK2;
363     carry |= (v != rp[nl]);
364     carry &= (v <= rp[nl]);
365     rp[nl] = v;
366   }
367 
368   if (bn_wexpand(ret, nl) == NULL) {
369     return 0;
370   }
371   ret->top = nl;
372   ret->neg = r->neg;
373 
374   rp = ret->d;
375   ap = &(r->d[nl]);
376 
377   {
378     BN_ULONG *nrp;
379     size_t m;
380 
381     v = bn_sub_words(rp, ap, np, nl) - carry;
382     /* if subtraction result is real, then trick unconditional memcpy below to
383      * perform in-place "refresh" instead of actual copy. */
384     m = (0 - (size_t)v);
385     nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m));
386 
387     for (i = 0, nl -= 4; i < nl; i += 4) {
388       BN_ULONG t1, t2, t3, t4;
389 
390       t1 = nrp[i + 0];
391       t2 = nrp[i + 1];
392       t3 = nrp[i + 2];
393       ap[i + 0] = 0;
394       t4 = nrp[i + 3];
395       ap[i + 1] = 0;
396       rp[i + 0] = t1;
397       ap[i + 2] = 0;
398       rp[i + 1] = t2;
399       ap[i + 3] = 0;
400       rp[i + 2] = t3;
401       rp[i + 3] = t4;
402     }
403 
404     for (nl += 4; i < nl; i++) {
405       rp[i] = nrp[i], ap[i] = 0;
406     }
407   }
408 
409   bn_correct_top(r);
410   bn_correct_top(ret);
411 
412   return 1;
413 }
414 #endif
415 
416 #define PTR_SIZE_INT size_t
417 
BN_from_montgomery_word(BIGNUM * ret,BIGNUM * r,const BN_MONT_CTX * mont)418 static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont)
419 	{
420 	BIGNUM *n;
421 	BN_ULONG *ap,*np,*rp,n0,v,carry;
422 	int nl,max,i;
423 
424 	n= (BIGNUM*) &(mont->N);
425 	nl=n->top;
426 	if (nl == 0) { ret->top=0; return(1); }
427 
428 	max=(2*nl); /* carry is stored separately */
429 	if (bn_wexpand(r,max) == NULL) return(0);
430 
431 	r->neg^=n->neg;
432 	np=n->d;
433 	rp=r->d;
434 
435 	/* clear the top words of T */
436 #if 1
437 	for (i=r->top; i<max; i++) /* memset? XXX */
438 		rp[i]=0;
439 #else
440 	memset(&(rp[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
441 #endif
442 
443 	r->top=max;
444 	n0=mont->n0[0];
445 
446 	for (carry=0, i=0; i<nl; i++, rp++)
447 		{
448 		v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
449 		v = (v+carry+rp[nl])&BN_MASK2;
450 		carry |= (v != rp[nl]);
451 		carry &= (v <= rp[nl]);
452 		rp[nl]=v;
453 		}
454 
455 	if (bn_wexpand(ret,nl) == NULL) return(0);
456 	ret->top=nl;
457 	ret->neg=r->neg;
458 
459 	rp=ret->d;
460 	ap=&(r->d[nl]);
461 
462 	{
463 	BN_ULONG *nrp;
464 	size_t m;
465 
466 	v=bn_sub_words(rp,ap,np,nl)-carry;
467 	/* if subtraction result is real, then
468 	 * trick unconditional memcpy below to perform in-place
469 	 * "refresh" instead of actual copy. */
470 	m=(0-(size_t)v);
471 	nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m));
472 
473 	for (i=0,nl-=4; i<nl; i+=4)
474 		{
475 		BN_ULONG t1,t2,t3,t4;
476 
477 		t1=nrp[i+0];
478 		t2=nrp[i+1];
479 		t3=nrp[i+2];	ap[i+0]=0;
480 		t4=nrp[i+3];	ap[i+1]=0;
481 		rp[i+0]=t1;	ap[i+2]=0;
482 		rp[i+1]=t2;	ap[i+3]=0;
483 		rp[i+2]=t3;
484 		rp[i+3]=t4;
485 		}
486 	for (nl+=4; i<nl; i++)
487 		rp[i]=nrp[i], ap[i]=0;
488 	}
489 	bn_correct_top(r);
490 	bn_correct_top(ret);
491 
492 	return(1);
493 	}
494 
BN_from_montgomery(BIGNUM * ret,const BIGNUM * a,const BN_MONT_CTX * mont,BN_CTX * ctx)495 int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont,
496                        BN_CTX *ctx) {
497   int retn = 0;
498   BIGNUM *t;
499 
500   BN_CTX_start(ctx);
501   t = BN_CTX_get(ctx);
502   if (t == NULL) {
503     return 0;
504   }
505 
506   if (BN_copy(t, a)) {
507     retn = BN_from_montgomery_word(ret, t, mont);
508   }
509   BN_CTX_end(ctx);
510 
511   return retn;
512 }
513 
BN_mod_mul_montgomery(BIGNUM * r,const BIGNUM * a,const BIGNUM * b,const BN_MONT_CTX * mont,BN_CTX * ctx)514 int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
515                           const BN_MONT_CTX *mont, BN_CTX *ctx) {
516   BIGNUM *tmp;
517   int ret = 0;
518 
519 #if defined(OPENSSL_BN_ASM_MONT)
520   int num = mont->N.top;
521 
522   if (num > 1 && a->top == num && b->top == num) {
523     if (bn_wexpand(r, num) == NULL) {
524       return 0;
525     }
526     if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) {
527       r->neg = a->neg ^ b->neg;
528       r->top = num;
529       bn_correct_top(r);
530       return 1;
531     }
532   }
533 #endif
534 
535   BN_CTX_start(ctx);
536   tmp = BN_CTX_get(ctx);
537   if (tmp == NULL) {
538     goto err;
539   }
540 
541   if (a == b) {
542     if (!BN_sqr(tmp, a, ctx)) {
543       goto err;
544     }
545   } else {
546     if (!BN_mul(tmp, a, b, ctx)) {
547       goto err;
548     }
549   }
550 
551   /* reduce from aRR to aR */
552   if (!BN_from_montgomery_word(r, tmp, mont)) {
553     goto err;
554   }
555 
556   ret = 1;
557 
558 err:
559   BN_CTX_end(ctx);
560   return ret;
561 }
562