diff --git a/lib/hcrypto/Makefile.am b/lib/hcrypto/Makefile.am index 9a5d08dc0..fe41a1998 100644 --- a/lib/hcrypto/Makefile.am +++ b/lib/hcrypto/Makefile.am @@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.am.common -AM_CPPFLAGS += -I$(srcdir)/tomsfastmath/src/headers +AM_CPPFLAGS += -I$(srcdir)/tomsfastmath/src/headers -I$(srcdir)/libtommath lib_LTLIBRARIES = libhcrypto.la check_LTLIBRARIES = libhctest.la @@ -93,6 +93,7 @@ LDADD = $(lib_LTLIBRARIES) $(LIB_roken) libhcrypto_la_SOURCES = \ $(imathsource) \ $(tfmsource) \ + $(ltmsources) \ aes.c \ aes.h \ bn.c \ @@ -146,6 +147,7 @@ libhcrypto_la_SOURCES = \ rsa-gmp.c \ rsa-imath.c \ rsa-tfm.c \ + rsa-ltm.c \ rsa.h \ sha.c \ sha.h \ @@ -250,6 +252,131 @@ tfmsource = \ tomsfastmath/src/sqr/fp_sqr_comba_small_set.c \ tomsfastmath/src/sqr/fp_sqrmod.c +ltmsources = \ + libtommath/bncore.c \ + libtommath/bn_mp_init.c \ + libtommath/bn_mp_clear.c \ + libtommath/bn_mp_exch.c \ + libtommath/bn_mp_grow.c \ + libtommath/bn_mp_shrink.c \ + libtommath/bn_mp_clamp.c \ + libtommath/bn_mp_zero.c \ + libtommath/bn_mp_zero_multi.c \ + libtommath/bn_mp_set.c \ + libtommath/bn_mp_set_int.c \ + libtommath/bn_mp_init_size.c \ + libtommath/bn_mp_copy.c \ + libtommath/bn_mp_init_copy.c \ + libtommath/bn_mp_abs.c \ + libtommath/bn_mp_neg.c \ + libtommath/bn_mp_cmp_mag.c \ + libtommath/bn_mp_cmp.c \ + libtommath/bn_mp_cmp_d.c \ + libtommath/bn_mp_rshd.c \ + libtommath/bn_mp_lshd.c \ + libtommath/bn_mp_mod_2d.c \ + libtommath/bn_mp_div_2d.c \ + libtommath/bn_mp_mul_2d.c \ + libtommath/bn_mp_div_2.c \ + libtommath/bn_mp_mul_2.c \ + libtommath/bn_s_mp_add.c \ + libtommath/bn_s_mp_sub.c \ + libtommath/bn_fast_s_mp_mul_digs.c \ + libtommath/bn_s_mp_mul_digs.c \ + libtommath/bn_fast_s_mp_mul_high_digs.c \ + libtommath/bn_s_mp_mul_high_digs.c \ + libtommath/bn_fast_s_mp_sqr.c \ + libtommath/bn_s_mp_sqr.c \ + libtommath/bn_mp_add.c \ + libtommath/bn_mp_sub.c \ + libtommath/bn_mp_karatsuba_mul.c \ + libtommath/bn_mp_mul.c \ + libtommath/bn_mp_karatsuba_sqr.c \ + libtommath/bn_mp_sqr.c \ + libtommath/bn_mp_div.c \ + libtommath/bn_mp_mod.c \ + libtommath/bn_mp_add_d.c \ + libtommath/bn_mp_sub_d.c \ + libtommath/bn_mp_mul_d.c \ + libtommath/bn_mp_div_d.c \ + libtommath/bn_mp_mod_d.c \ + libtommath/bn_mp_expt_d.c \ + libtommath/bn_mp_addmod.c \ + libtommath/bn_mp_submod.c \ + libtommath/bn_mp_mulmod.c \ + libtommath/bn_mp_sqrmod.c \ + libtommath/bn_mp_gcd.c \ + libtommath/bn_mp_lcm.c \ + libtommath/bn_fast_mp_invmod.c \ + libtommath/bn_mp_invmod.c \ + libtommath/bn_mp_reduce.c \ + libtommath/bn_mp_montgomery_setup.c \ + libtommath/bn_fast_mp_montgomery_reduce.c \ + libtommath/bn_mp_montgomery_reduce.c \ + libtommath/bn_mp_exptmod_fast.c \ + libtommath/bn_mp_exptmod.c \ + libtommath/bn_mp_2expt.c \ + libtommath/bn_mp_n_root.c \ + libtommath/bn_mp_jacobi.c \ + libtommath/bn_reverse.c \ + libtommath/bn_mp_count_bits.c \ + libtommath/bn_mp_read_unsigned_bin.c \ + libtommath/bn_mp_read_signed_bin.c \ + libtommath/bn_mp_to_unsigned_bin.c \ + libtommath/bn_mp_to_signed_bin.c \ + libtommath/bn_mp_unsigned_bin_size.c \ + libtommath/bn_mp_signed_bin_size.c \ + libtommath/bn_mp_xor.c \ + libtommath/bn_mp_and.c \ + libtommath/bn_mp_or.c \ + libtommath/bn_mp_rand.c \ + libtommath/bn_mp_montgomery_calc_normalization.c \ + libtommath/bn_mp_prime_is_divisible.c \ + libtommath/bn_prime_tab.c \ + libtommath/bn_mp_prime_fermat.c \ + libtommath/bn_mp_prime_miller_rabin.c \ + libtommath/bn_mp_prime_is_prime.c \ + libtommath/bn_mp_prime_next_prime.c \ + libtommath/bn_mp_find_prime.c \ + libtommath/bn_mp_isprime.c \ + libtommath/bn_mp_dr_reduce.c \ + libtommath/bn_mp_dr_is_modulus.c \ + libtommath/bn_mp_dr_setup.c \ + libtommath/bn_mp_reduce_setup.c \ + libtommath/bn_mp_toom_mul.c \ + libtommath/bn_mp_toom_sqr.c \ + libtommath/bn_mp_div_3.c \ + libtommath/bn_s_mp_exptmod.c \ + libtommath/bn_mp_reduce_2k.c \ + libtommath/bn_mp_reduce_is_2k.c \ + libtommath/bn_mp_reduce_2k_setup.c \ + libtommath/bn_mp_reduce_2k_l.c \ + libtommath/bn_mp_reduce_is_2k_l.c \ + libtommath/bn_mp_reduce_2k_setup_l.c \ + libtommath/bn_mp_radix_smap.c \ + libtommath/bn_mp_read_radix.c \ + libtommath/bn_mp_toradix.c \ + libtommath/bn_mp_radix_size.c \ + libtommath/bn_mp_fread.c \ + libtommath/bn_mp_fwrite.c \ + libtommath/bn_mp_cnt_lsb.c \ + libtommath/bn_error.c \ + libtommath/bn_mp_init_multi.c \ + libtommath/bn_mp_clear_multi.c \ + libtommath/bn_mp_exteuclid.c \ + libtommath/bn_mp_toradix_n.c \ + libtommath/bn_mp_prime_random_ex.c \ + libtommath/bn_mp_get_int.c \ + libtommath/bn_mp_sqrt.c \ + libtommath/bn_mp_is_square.c \ + libtommath/bn_mp_init_set.c \ + libtommath/bn_mp_init_set_int.c \ + libtommath/bn_mp_invmod_slow.c \ + libtommath/bn_mp_prime_rabin_miller_trials.c \ + libtommath/bn_mp_to_signed_bin_n.c \ + libtommath/bn_mp_to_unsigned_bin_n.c + + $(libhcrypto_la_OBJECTS): hcrypto-link libhcrypto_la_CPPFLAGS = -DIMATH_LARGE_PRIME_TABLE -DTFM_CHECK -DTFM_TIMING_RESISTANT -DBUILD_HCRYPTO_LIB $(AM_CPPFLAGS) diff --git a/lib/hcrypto/engine.c b/lib/hcrypto/engine.c index c3979fd63..1db99f903 100644 --- a/lib/hcrypto/engine.c +++ b/lib/hcrypto/engine.c @@ -258,6 +258,26 @@ ENGINE_load_builtin_engines(void) ENGINE_set_RSA(engine, RSA_tfm_method()); ENGINE_set_DH(engine, DH_tfm_method()); + ret = add_engine(engine); + if (ret != 1) + ENGINE_finish(engine); + + /* + * ltm + */ + + engine = ENGINE_new(); + if (engine == NULL) + return; + + ENGINE_set_id(engine, "ltm"); + ENGINE_set_name(engine, + "Heimdal crypto ltm engine version " PACKAGE_VERSION); + ENGINE_set_RSA(engine, RSA_ltm_method()); +#if 0 + ENGINE_set_DH(engine, DH_ltm_method()); +#endif + ret = add_engine(engine); if (ret != 1) ENGINE_finish(engine); diff --git a/lib/hcrypto/libtommath/bn_mp_find_prime.c b/lib/hcrypto/libtommath/bn_mp_find_prime.c new file mode 100644 index 000000000..0458744fc --- /dev/null +++ b/lib/hcrypto/libtommath/bn_mp_find_prime.c @@ -0,0 +1,26 @@ +/* TomsFastMath, a fast ISO C bignum library. + * + * This project is public domain and free for all purposes. + * + * Love Hornquist Astrand + */ +#include + +int mp_find_prime(mp_int *a) +{ + int res; + + if (mp_iseven(a)) + mp_add_d(a, 1, a); + + do { + + if ((res = mp_isprime(a)) == MP_NO) { + mp_add_d(a, 2, a); + continue; + } + + } while (res != MP_YES); + + return res; +} diff --git a/lib/hcrypto/libtommath/bn_mp_isprime.c b/lib/hcrypto/libtommath/bn_mp_isprime.c new file mode 100644 index 000000000..07ce86f29 --- /dev/null +++ b/lib/hcrypto/libtommath/bn_mp_isprime.c @@ -0,0 +1,75 @@ +/* TomsFastMath, a fast ISO C bignum library. + * + * This project is meant to fill in where LibTomMath + * falls short. That is speed ;-) + * + * This project is public domain and free for all purposes. + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include + +/* a few primes */ +static const mp_digit primes[256] = { + 0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013, + 0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035, + 0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059, + 0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083, + 0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD, + 0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF, + 0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107, + 0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137, + + 0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167, + 0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199, + 0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9, + 0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7, + 0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239, + 0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265, + 0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293, + 0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF, + + 0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301, + 0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B, + 0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371, + 0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD, + 0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5, + 0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419, + 0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449, + 0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B, + + 0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7, + 0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503, + 0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529, + 0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F, + 0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3, + 0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7, + 0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623, + 0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653 +}; + +int mp_isprime(mp_int *a) +{ + mp_int b; + mp_digit d; + int r, res; + + /* do trial division */ + for (r = 0; r < 256; r++) { + mp_mod_d(a, primes[r], &d); + if (d == 0) { + return MP_NO; + } + } + + /* now do 8 miller rabins */ + mp_init(&b); + for (r = 0; r < 128; r++) { + mp_set(&b, primes[r]); + mp_prime_miller_rabin(a, &b, &res); + if (res == MP_NO) { + return MP_NO; + } + } + return MP_YES; +} diff --git a/lib/hcrypto/libtommath/bn_mp_zero_multi.c b/lib/hcrypto/libtommath/bn_mp_zero_multi.c new file mode 100644 index 000000000..339a75fbf --- /dev/null +++ b/lib/hcrypto/libtommath/bn_mp_zero_multi.c @@ -0,0 +1,35 @@ +#include +#ifdef BN_MP_ZERO_MULTI_C +/* LibTomMath, multiple-precision integer library -- Tom St Denis + * + * LibTomMath is a library that provides multiple-precision + * integer arithmetic as well as number theoretic functionality. + * + * The library was designed directly after the MPI library by + * Michael Fromberger but has been written from scratch with + * additional optimizations in place. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ +#include + +/* set to zero */ +void mp_zero_multi (mp_int * mp, ...) +{ + mp_int* next_mp = mp; + va_list args; + va_start(args, mp); + while (next_mp != NULL) { + mp_zero(next_mp); + next_mp = va_arg(args, mp_int*); + } + va_end(args); +} +#endif + +/* $Source: /cvs/libtom/libtommath/bn_mp_zero.c,v $ */ +/* $Revision: 1.4 $ */ +/* $Date: 2006/12/28 01:25:13 $ */ diff --git a/lib/hcrypto/libtommath/tommath.h b/lib/hcrypto/libtommath/tommath.h index 3c00b9e13..426207a29 100644 --- a/lib/hcrypto/libtommath/tommath.h +++ b/lib/hcrypto/libtommath/tommath.h @@ -79,7 +79,7 @@ extern "C" { #define DIGIT_BIT 60 #else /* this is the default case, 28-bit digits */ - + /* this is to make porting into LibTomCrypt easier :-) */ #ifndef CRYPT #if defined(_MSC_VER) || defined(__BORLANDC__) @@ -221,10 +221,14 @@ int mp_init_size(mp_int *a, int size); #define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) #define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) #define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) +#define mp_isneg(a) (((a)->sign) ? MP_YES : MP_NO) /* set to zero */ void mp_zero(mp_int *a); +/* set to zero, multi */ +void mp_zero_multi(mp_int *a, ...); + /* set to a digit */ void mp_set(mp_int *a, mp_digit b); @@ -516,6 +520,10 @@ int mp_prime_next_prime(mp_int *a, int t, int bbs_style); */ int mp_prime_random_ex(mp_int *a, int t, int size, int flags, ltm_prime_callback cb, void *dat); +int mp_find_prime(mp_int *a); + +int mp_isprime(mp_int *a); + /* ---> radix conversion <--- */ int mp_count_bits(mp_int *a); diff --git a/lib/hcrypto/libtommath/tommath_class.h b/lib/hcrypto/libtommath/tommath_class.h index 166dd80e5..fa95a0277 100644 --- a/lib/hcrypto/libtommath/tommath_class.h +++ b/lib/hcrypto/libtommath/tommath_class.h @@ -118,6 +118,7 @@ #define BN_MP_UNSIGNED_BIN_SIZE_C #define BN_MP_XOR_C #define BN_MP_ZERO_C +#define BN_MP_ZERO_MULTI_C #define BN_PRIME_TAB_C #define BN_REVERSE_C #define BN_S_MP_ADD_C diff --git a/lib/hcrypto/rsa-ltm.c b/lib/hcrypto/rsa-ltm.c new file mode 100644 index 000000000..214cd7f5e --- /dev/null +++ b/lib/hcrypto/rsa-ltm.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2006 - 2007, 2010 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include + +#include + +#include + +#include "tommath.h" + +static void +BN2mpz(mp_int *s, const BIGNUM *bn) +{ + size_t len; + void *p; + + mp_init(s); + + len = BN_num_bytes(bn); + p = malloc(len); + BN_bn2bin(bn, p); + mp_read_unsigned_bin(s, p, len); + free(p); +} + +static int +ltm_rsa_private_calculate(mp_int * in, mp_int * p, mp_int * q, + mp_int * dmp1, mp_int * dmq1, mp_int * iqmp, + mp_int * out) +{ + mp_int vp, vq, u; + + mp_init_multi(&vp, &vq, &u, NULL); + + /* vq = c ^ (d mod (q - 1)) mod q */ + /* vp = c ^ (d mod (p - 1)) mod p */ + mp_mod(in, p, &u); + mp_exptmod(&u, dmp1, p, &vp); + mp_mod(in, q, &u); + mp_exptmod(&u, dmq1, q, &vq); + + /* C2 = 1/q mod p (iqmp) */ + /* u = (vp - vq)C2 mod p. */ + mp_sub(&vp, &vq, &u); + if (mp_isneg(&u)) + mp_add(&u, p, &u); + mp_mul(&u, iqmp, &u); + mp_mod(&u, p, &u); + + /* c ^ d mod n = vq + u q */ + mp_mul(&u, q, &u); + mp_add(&u, &vq, out); + + mp_zero_multi(&vp, &vq, &u, NULL); + + return 0; +} + +/* + * + */ + +static int +ltm_rsa_public_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + int res; + size_t size, padlen; + mp_int enc, dec, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + p = p0 = malloc(size - 1); + if (p0 == NULL) { + mp_zero_multi(&e, &n, NULL); + return -3; + } + + padlen = size - flen - 3; + + *p++ = 2; + if (RAND_bytes(p, padlen) != 1) { + mp_zero_multi(&e, &n, NULL); + free(p0); + return -4; + } + while(padlen) { + if (*p == 0) + *p = 1; + padlen--; + p++; + } + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size - 1); + + mp_init_multi(&enc, &dec, NULL); + mp_read_unsigned_bin(&dec, p0, size - 1); + free(p0); + + res = mp_exptmod(&dec, &e, &n, &enc); + + mp_zero_multi(&dec, &e, &n, NULL); + + if (res != 0) + return -4; + + { + size_t ssize; + ssize = mp_unsigned_bin_size(&enc); + assert(size >= ssize); + mp_to_unsigned_bin(&enc, to); + size = ssize; + } + mp_zero(&enc); + + return size; +} + +static int +ltm_rsa_public_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p; + int res; + size_t size; + mp_int s, us, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + if (flen > RSA_size(rsa)) + return -2; + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + +#if 0 + /* Check that the exponent is larger then 3 */ + if (mp_int_compare_value(&e, 3) <= 0) { + mp_zero_multi(&e, &n, NULL); + return -3; + } +#endif + + mp_init_multi(&s, &us, NULL); + mp_read_unsigned_bin(&s, rk_UNCONST(from), flen); + + if (mp_cmp(&s, &n) >= 0) { + mp_zero_multi(&e, &n, NULL); + return -4; + } + + res = mp_exptmod(&s, &e, &n, &us); + + mp_zero_multi(&s, &e, &n, NULL); + + if (res != 0) + return -5; + p = to; + + + size = mp_unsigned_bin_size(&us); + assert(size <= RSA_size(rsa)); + mp_to_unsigned_bin(&us, p); + + mp_zero(&us); + + /* head zero was skipped by mp_to_unsigned_bin */ + if (*p == 0) + return -6; + if (*p != 1) + return -7; + size--; p++; + while (size && *p == 0xff) { + size--; p++; + } + if (size == 0 || *p != 0) + return -8; + size--; p++; + + memmove(to, p, size); + + return size; +} + +static int +ltm_rsa_private_encrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *p, *p0; + int res; + int size; + mp_int in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + + if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) + return -2; + + p0 = p = malloc(size); + *p++ = 0; + *p++ = 1; + memset(p, 0xff, size - flen - 3); + p += size - flen - 3; + *p++ = 0; + memcpy(p, from, flen); + p += flen; + assert((p - p0) == size); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + mp_init_multi(&in, &out, NULL); + mp_read_unsigned_bin(&in, p0, size); + free(p0); + + if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) { + size = -3; + goto out; + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mp_int p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + mp_zero_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + + if (res != 0) { + size = -4; + goto out; + } + } else { + mp_int d; + + BN2mpz(&d, rsa->d); + res = mp_exptmod(&in, &d, &n, &out); + mp_zero(&d); + if (res != 0) { + size = -5; + goto out; + } + } + + if (size > 0) { + size_t ssize; + ssize = mp_unsigned_bin_size(&out); + assert(size >= ssize); + mp_to_unsigned_bin(&out, to); + size = ssize; + } + + out: + mp_zero_multi(&e, &n, &in, &out, NULL); + + return size; +} + +static int +ltm_rsa_private_decrypt(int flen, const unsigned char* from, + unsigned char* to, RSA* rsa, int padding) +{ + unsigned char *ptr; + int res; + size_t size; + mp_int in, out, n, e; + + if (padding != RSA_PKCS1_PADDING) + return -1; + + size = RSA_size(rsa); + if (flen > size) + return -2; + + mp_init_multi(&in, &out, NULL); + + BN2mpz(&n, rsa->n); + BN2mpz(&e, rsa->e); + + mp_read_unsigned_bin(&in, rk_UNCONST(from), flen); + + if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) { + size = -2; + goto out; + } + + if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { + mp_int p, q, dmp1, dmq1, iqmp; + + BN2mpz(&p, rsa->p); + BN2mpz(&q, rsa->q); + BN2mpz(&dmp1, rsa->dmp1); + BN2mpz(&dmq1, rsa->dmq1); + BN2mpz(&iqmp, rsa->iqmp); + + res = ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); + + mp_zero_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); + + if (res != 0) { + size = -3; + goto out; + } + + } else { + mp_int d; + + if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) + return -4; + + BN2mpz(&d, rsa->d); + res = mp_exptmod(&in, &d, &n, &out); + mp_zero(&d); + if (res != 0) { + size = -5; + goto out; + } + } + + ptr = to; + { + size_t ssize; + ssize = mp_unsigned_bin_size(&out); + assert(size >= ssize); + mp_to_unsigned_bin(&out, ptr); + size = ssize; + } + + /* head zero was skipped by mp_int_to_unsigned */ + if (*ptr != 2) { + size = -6; + goto out; + } + size--; ptr++; + while (size && *ptr != 0) { + size--; ptr++; + } + if (size == 0) + return -7; + size--; ptr++; + + memmove(to, ptr, size); + + out: + mp_zero_multi(&e, &n, &in, &out, NULL); + + return size; +} + +static BIGNUM * +mpz2BN(mp_int *s) +{ + size_t size; + BIGNUM *bn; + void *p; + + size = mp_unsigned_bin_size(s); + p = malloc(size); + if (p == NULL && size != 0) + return NULL; + + mp_to_unsigned_bin(s, p); + + bn = BN_bin2bn(p, size, NULL); + free(p); + return bn; +} + +static int +random_num(mp_int *num, size_t len) +{ + unsigned char *p; + + len = (len + 7) / 8; + p = malloc(len); + if (p == NULL) + return 1; + if (RAND_bytes(p, len) != 1) { + free(p); + return 1; + } + mp_read_unsigned_bin(num, p, len); + free(p); + return 0; +} + +#define CHECK(f, v) if ((f) != (v)) { goto out; } + +static int +ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) +{ + mp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; + int counter, ret, bitsp; + + if (bits < 789) + return -1; + + bitsp = (bits + 1) / 2; + + ret = -1; + + mp_init_multi(&el, &p, &q, &n, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); + + BN2mpz(&el, e); + + /* generate p and q so that p != q and bits(pq) ~ bits */ + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&p, bitsp), 0); + CHECK(mp_find_prime(&p), MP_YES); + + mp_sub_d(&p, 1, &t1); + mp_gcd(&t1, &el, &t2); + } while(mp_cmp_d(&t2, 1) != 0); + + BN_GENCB_call(cb, 3, 0); + + counter = 0; + do { + BN_GENCB_call(cb, 2, counter++); + CHECK(random_num(&q, bits - bitsp), 0); + CHECK(mp_find_prime(&q), MP_YES); + + if (mp_cmp(&p, &q) == 0) /* don't let p and q be the same */ + continue; + + mp_sub_d(&q, 1, &t1); + mp_gcd(&t1, &el, &t2); + } while(mp_cmp_d(&t2, 1) != 0); + + /* make p > q */ + if (mp_cmp(&p, &q) < 0) { + mp_int c; + c = p; + p = q; + q = c; + } + + BN_GENCB_call(cb, 3, 1); + + /* calculate n, n = p * q */ + mp_mul(&p, &q, &n); + + /* calculate d, d = 1/e mod (p - 1)(q - 1) */ + mp_sub_d(&p, 1, &t1); + mp_sub_d(&q, 1, &t2); + mp_mul(&t1, &t2, &t3); + mp_invmod(&el, &t3, &d); + + /* calculate dmp1 dmp1 = d mod (p-1) */ + mp_mod(&d, &t1, &dmp1); + /* calculate dmq1 dmq1 = d mod (q-1) */ + mp_mod(&d, &t2, &dmq1); + /* calculate iqmp iqmp = 1/q mod p */ + mp_invmod(&q, &p, &iqmp); + + /* fill in RSA key */ + + rsa->e = mpz2BN(&el); + rsa->p = mpz2BN(&p); + rsa->q = mpz2BN(&q); + rsa->n = mpz2BN(&n); + rsa->d = mpz2BN(&d); + rsa->dmp1 = mpz2BN(&dmp1); + rsa->dmq1 = mpz2BN(&dmq1); + rsa->iqmp = mpz2BN(&iqmp); + + ret = 1; + +out: + mp_zero_multi(&el, &p, &q, &n, &d, &dmp1, + &dmq1, &iqmp, &t1, &t2, &t3, NULL); + + return ret; +} + +static int +ltm_rsa_init(RSA *rsa) +{ + return 1; +} + +static int +ltm_rsa_finish(RSA *rsa) +{ + return 1; +} + +const RSA_METHOD hc_rsa_ltm_method = { + "hcrypto ltm RSA", + ltm_rsa_public_encrypt, + ltm_rsa_public_decrypt, + ltm_rsa_private_encrypt, + ltm_rsa_private_decrypt, + NULL, + NULL, + ltm_rsa_init, + ltm_rsa_finish, + 0, + NULL, + NULL, + NULL, + ltm_rsa_generate_key +}; + +const RSA_METHOD * +RSA_ltm_method(void) +{ + return &hc_rsa_ltm_method; +} diff --git a/lib/hcrypto/rsa.h b/lib/hcrypto/rsa.h index 3e5fe7eb4..4f247c7c1 100644 --- a/lib/hcrypto/rsa.h +++ b/lib/hcrypto/rsa.h @@ -42,6 +42,7 @@ #define RSA_null_method hc_RSA_null_method #define RSA_imath_method hc_RSA_imath_method #define RSA_tfm_method hc_RSA_tfm_method +#define RSA_ltm_method hc_RSA_ltm_method #define RSA_gmp_method hc_RSA_gmp_method #define RSA_new hc_RSA_new #define RSA_new_method hc_RSA_new_method @@ -138,6 +139,7 @@ const RSA_METHOD *RSA_null_method(void); const RSA_METHOD *RSA_imath_method(void); const RSA_METHOD *RSA_gmp_method(void); const RSA_METHOD *RSA_tfm_method(void); +const RSA_METHOD *RSA_ltm_method(void); /* * diff --git a/lib/hcrypto/version-script.map b/lib/hcrypto/version-script.map index 4ba27d359..058fc2386 100644 --- a/lib/hcrypto/version-script.map +++ b/lib/hcrypto/version-script.map @@ -70,6 +70,7 @@ HEIMDAL_CRYPTO_1.0 { hc_DH_get_ex_data; hc_DH_imath_method; hc_DH_tfm_method; + hc_DH_ltm_method; hc_DH_gmp_method; hc_DH_new; hc_DH_new_method;