diff --git a/CHANGES b/CHANGES index 1aa60fadd3db34ea5cc114e25377fe77a8f28aa3..66adadf61ca0314492efcb9511ec67a67c5fa872 100644 --- a/CHANGES +++ b/CHANGES @@ -681,6 +681,11 @@ Changes between 0.9.8g and 0.9.8h [xx XXX xxxx] + *) Update the GMP engine glue to do direct copies between BIGNUM and + mpz_t when openssl and GMP use the same limb size. Otherwise the + existing "conversion via a text string export" trick is still used. + [Paul Sheer , Geoff Thorpe] + *) Zlib compression BIO. This is a filter BIO which compressed and uncompresses any data passed through it. [Steve Henson] diff --git a/engines/e_gmp.c b/engines/e_gmp.c index 3b1f4b9cb9fb2e822bcedcd30a54cbb2ddaab98a..97bc2142a112c8e61b28b64a8f0b1d23315dd050 100644 --- a/engines/e_gmp.c +++ b/engines/e_gmp.c @@ -85,6 +85,8 @@ #include #include #include +#include +#include #ifndef OPENSSL_NO_HW #ifndef OPENSSL_NO_GMP @@ -251,27 +253,61 @@ static int e_gmp_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void)) return to_return; } -/* HACK - use text I/O functions in openssl and GMP to handle conversions. This - * is vile. */ + +/* Most often limb sizes will be the same. If not, we use hex conversion + * which is neat, but extremely inefficient. */ static int bn2gmp(const BIGNUM *bn, mpz_t g) { - int toret; - char *tmpchar = BN_bn2hex(bn); - if(!tmpchar) return 0; - toret = (mpz_set_str(g, tmpchar, 16) == 0 ? 1 : 0); - OPENSSL_free(tmpchar); - return toret; + bn_check_top(bn); + if(((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) && + (BN_BITS2 == GMP_NUMB_BITS)) + { + /* The common case */ + if(!_mpz_realloc (g, bn->top)) + return 0; + memcpy(&g->_mp_d[0], &bn->d[0], bn->top * sizeof(bn->d[0])); + g->_mp_size = bn->top; + if(bn->neg) + g->_mp_size = -g->_mp_size; + return 1; + } + else + { + int toret; + char *tmpchar = BN_bn2hex(bn); + if(!tmpchar) return 0; + toret = (mpz_set_str(g, tmpchar, 16) == 0 ? 1 : 0); + OPENSSL_free(tmpchar); + return toret; + } } static int gmp2bn(mpz_t g, BIGNUM *bn) { - int toret; - char *tmpchar = OPENSSL_malloc(mpz_sizeinbase(g, 16) + 10); - if(!tmpchar) return 0; - mpz_get_str(tmpchar, 16, g); - toret = BN_hex2bn(&bn, tmpchar); - OPENSSL_free(tmpchar); - return toret; + if(((sizeof(bn->d[0]) * 8) == GMP_NUMB_BITS) && + (BN_BITS2 == GMP_NUMB_BITS)) + { + /* The common case */ + int s = (g->_mp_size >= 0) ? g->_mp_size : -g->_mp_size; + BN_zero(bn); + if(bn_expand2 (bn, s) == NULL) + return 0; + bn->top = s; + memcpy(&bn->d[0], &g->_mp_d[0], s * sizeof(bn->d[0])); + bn_correct_top(bn); + bn->neg = g->_mp_size >= 0 ? 0 : 1; + return 1; + } + else + { + int toret; + char *tmpchar = OPENSSL_malloc(mpz_sizeinbase(g, 16) + 10); + if(!tmpchar) return 0; + mpz_get_str(tmpchar, 16, g); + toret = BN_hex2bn(&bn, tmpchar); + OPENSSL_free(tmpchar); + return toret; + } } #ifndef OPENSSL_NO_RSA