static void check_primes (void) { gcry_error_t err = GPG_ERR_NO_ERROR; gcry_mpi_t *factors = NULL; gcry_mpi_t prime = NULL; gcry_mpi_t g; unsigned int i = 0; struct prime_spec { unsigned int prime_bits; unsigned int factor_bits; unsigned int flags; } prime_specs[] = { { 1024, 100, GCRY_PRIME_FLAG_SPECIAL_FACTOR }, { 128, 0, 0 }, { 0 }, }; for (i = 0; prime_specs[i].prime_bits; i++) { err = gcry_prime_generate (&prime, prime_specs[i].prime_bits, prime_specs[i].factor_bits, &factors, NULL, NULL, GCRY_WEAK_RANDOM, prime_specs[i].flags); assert (! err); if (verbose) { fprintf (stderr, "test %d: p = ", i); gcry_mpi_dump (prime); putc ('\n', stderr); } err = gcry_prime_check (prime, 0); assert (! err); err = gcry_prime_group_generator (&g, prime, factors, NULL); assert (!err); gcry_prime_release_factors (factors); factors = NULL; if (verbose) { fprintf (stderr, " %d: g = ", i); gcry_mpi_dump (g); putc ('\n', stderr); } gcry_mpi_release (g); gcry_mpi_add_ui (prime, prime, 1); err = gcry_prime_check (prime, 0); assert (err); } }
/* Convience function used internally. */ void _gcry_log_mpidump (const char *text, gcry_mpi_t a) { log_printf ("%s:", text); gcry_mpi_dump (a); log_printf ("\n"); }
gpointer egg_dh_gen_secret (gcry_mpi_t peer, gcry_mpi_t priv, gcry_mpi_t prime, gsize *bytes) { gcry_error_t gcry; guchar *value; gsize n_value; gcry_mpi_t k; gint bits; g_return_val_if_fail (peer, NULL); g_return_val_if_fail (priv, NULL); g_return_val_if_fail (prime, NULL); bits = gcry_mpi_get_nbits (prime); g_return_val_if_fail (bits >= 0, NULL); k = gcry_mpi_snew (bits); g_return_val_if_fail (k, NULL); gcry_mpi_powm (k, peer, priv, prime); /* Write out the secret */ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_value, k); g_return_val_if_fail (gcry == 0, NULL); value = egg_secure_alloc (n_value); gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value, n_value, &n_value, k); g_return_val_if_fail (gcry == 0, NULL); #if DEBUG_DH_SECRET g_printerr ("DH SECRET: "); gcry_mpi_dump (k); gcry_mpi_release (k); #endif *bytes = n_value; #if DEBUG_DH_SECRET gcry_mpi_scan (&k, GCRYMPI_FMT_USG, value, bytes, NULL); g_printerr ("RAW SECRET: "); gcry_mpi_dump (k); gcry_mpi_release (k); #endif return value; }
static GVariant * request_open_session_aes (SecretSession *session) { gcry_error_t gcry; gcry_mpi_t base; unsigned char *buffer; size_t n_buffer; GVariant *argument; g_assert (session->prime == NULL); g_assert (session->privat == NULL); g_assert (session->publi == NULL); egg_libgcrypt_initialize (); /* Initialize our local parameters and values */ if (!egg_dh_default_params ("ietf-ike-grp-modp-1024", &session->prime, &base)) g_return_val_if_reached (NULL); #if 0 g_printerr ("\n lib prime: "); gcry_mpi_dump (session->prime); g_printerr ("\n lib base: "); gcry_mpi_dump (base); g_printerr ("\n"); #endif if (!egg_dh_gen_pair (session->prime, base, 0, &session->publi, &session->privat)) g_return_val_if_reached (NULL); gcry_mpi_release (base); gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, session->publi); g_return_val_if_fail (gcry == 0, NULL); argument = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), buffer, n_buffer, TRUE, gcry_free, buffer); return g_variant_new ("(sv)", ALGORITHMS_AES, argument); }
/* Find a generator for PRIME where the factorization of (prime-1) is in the NULL terminated array FACTORS. Return the generator as a newly allocated MPI in R_G. If START_G is not NULL, use this as s atart for the search. Returns 0 on success.*/ gcry_error_t gcry_prime_group_generator (gcry_mpi_t *r_g, gcry_mpi_t prime, gcry_mpi_t *factors, gcry_mpi_t start_g) { gcry_mpi_t tmp = gcry_mpi_new (0); gcry_mpi_t b = gcry_mpi_new (0); gcry_mpi_t pmin1 = gcry_mpi_new (0); gcry_mpi_t g = start_g? gcry_mpi_copy (start_g) : gcry_mpi_set_ui (NULL, 3); int first = 1; int i, n; if (!factors || !r_g || !prime) return gpg_error (GPG_ERR_INV_ARG); *r_g = NULL; for (n=0; factors[n]; n++) ; if (n < 2) return gpg_error (GPG_ERR_INV_ARG); /* Extra sanity check - usually disabled. */ /* mpi_set (tmp, factors[0]); */ /* for(i = 1; i < n; i++) */ /* mpi_mul (tmp, tmp, factors[i]); */ /* mpi_add_ui (tmp, tmp, 1); */ /* if (mpi_cmp (prime, tmp)) */ /* return gpg_error (GPG_ERR_INV_ARG); */ gcry_mpi_sub_ui (pmin1, prime, 1); do { if (first) first = 0; else gcry_mpi_add_ui (g, g, 1); if (DBG_CIPHER) { log_debug ("checking g:"); gcry_mpi_dump (g); log_debug ("\n"); } else progress('^'); for (i = 0; i < n; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); gcry_mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); } while (i < n); gcry_mpi_release (tmp); gcry_mpi_release (b); gcry_mpi_release (pmin1); *r_g = g; return 0; }
/**************** * We do not need to use the strongest RNG because we gain no extra * security from it - The prime number is public and we could also * offer the factors for those who are willing to check that it is * indeed a strong prime. With ALL_FACTORS set to true all afcors of * prime-1 are returned in FACTORS. * * mode 0: Standard * 1: Make sure that at least one factor is of size qbits. */ static gcry_err_code_t prime_generate_internal (int mode, gcry_mpi_t *prime_generated, unsigned int pbits, unsigned int qbits, gcry_mpi_t g, gcry_mpi_t **ret_factors, gcry_random_level_t randomlevel, unsigned int flags, int all_factors, gcry_prime_check_func_t cb_func, void *cb_arg) { gcry_err_code_t err = 0; gcry_mpi_t *factors_new = NULL; /* Factors to return to the caller. */ gcry_mpi_t *factors = NULL; /* Current factors. */ gcry_mpi_t *pool = NULL; /* Pool of primes. */ unsigned char *perms = NULL; /* Permutations of POOL. */ gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ unsigned int fbits = 0; /* Length of prime factors. */ unsigned int n = 0; /* Number of factors. */ unsigned int m = 0; /* Number of primes in pool. */ gcry_mpi_t q = NULL; /* First prime factor. */ gcry_mpi_t prime = NULL; /* Prime candidate. */ unsigned int nprime = 0; /* Bits of PRIME. */ unsigned int req_qbits; /* The original QBITS value. */ gcry_mpi_t val_2; /* For check_prime(). */ unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); unsigned int count1 = 0, count2 = 0; unsigned int i = 0, j = 0; if (pbits < 48) return GPG_ERR_INV_ARG; /* If QBITS is not given, assume a reasonable value. */ if (!qbits) qbits = pbits / 3; req_qbits = qbits; /* Find number of needed prime factors. */ for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) ; n--; val_2 = mpi_alloc_set_ui (2); if ((! n) || ((mode == 1) && (n < 2))) { err = GPG_ERR_INV_ARG; goto leave; } if (mode == 1) { n--; fbits = (pbits - 2 * req_qbits -1) / n; qbits = pbits - req_qbits - n * fbits; } else { fbits = (pbits - req_qbits -1) / n; qbits = pbits - n * fbits; } if (DBG_CIPHER) log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", pbits, req_qbits, qbits, fbits, n); prime = gcry_mpi_new (pbits); /* Generate first prime factor. */ q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); if (mode == 1) q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); /* Allocate an array to hold the factors + 2 for later usage. */ factors = gcry_calloc (n + 2, sizeof (*factors)); if (!factors) { err = gpg_err_code_from_errno (errno); goto leave; } /* Make a pool of 3n+5 primes (this is an arbitrary value). */ m = n * 3 + 5; if (mode == 1) /* Need some more (for e.g. DSA). */ m += 5; if (m < 25) m = 25; pool = gcry_calloc (m , sizeof (*pool)); if (! pool) { err = gpg_err_code_from_errno (errno); goto leave; } /* Permutate over the pool of primes. */ do { next_try: if (! perms) { /* Allocate new primes. */ for(i = 0; i < m; i++) { mpi_free (pool[i]); pool[i] = NULL; } /* Init m_out_of_n(). */ perms = gcry_calloc (1, m); if (! perms) { err = gpg_err_code_from_errno (errno); goto leave; } for(i = 0; i < n; i++) { perms[i] = 1; pool[i] = gen_prime (fbits, is_secret, randomlevel, NULL, NULL); factors[i] = pool[i]; } } else { m_out_of_n ((char*)perms, n, m); for (i = j = 0; (i < m) && (j < n); i++) if (perms[i]) { if(! pool[i]) pool[i] = gen_prime (fbits, 0, 1, NULL, NULL); factors[j++] = pool[i]; } if (i == n) { gcry_free (perms); perms = NULL; progress ('!'); goto next_try; /* Allocate new primes. */ } } /* Generate next prime candidate: p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. */ mpi_set (prime, q); mpi_mul_ui (prime, prime, 2); if (mode == 1) mpi_mul (prime, prime, q_factor); for(i = 0; i < n; i++) mpi_mul (prime, prime, factors[i]); mpi_add_ui (prime, prime, 1); nprime = mpi_get_nbits (prime); if (nprime < pbits) { if (++count1 > 20) { count1 = 0; qbits++; progress('>'); mpi_free (q); q = gen_prime (qbits, 0, 0, NULL, NULL); goto next_try; } } else count1 = 0; if (nprime > pbits) { if (++count2 > 20) { count2 = 0; qbits--; progress('<'); mpi_free (q); q = gen_prime (qbits, 0, 0, NULL, NULL); goto next_try; } } else count2 = 0; } while (! ((nprime == pbits) && check_prime (prime, val_2, cb_func, cb_arg))); if (DBG_CIPHER) { progress ('\n'); log_mpidump ("prime : ", prime); log_mpidump ("factor q: ", q); if (mode == 1) log_mpidump ("factor q0: ", q_factor); for (i = 0; i < n; i++) log_mpidump ("factor pi: ", factors[i]); log_debug ("bit sizes: prime=%u, q=%u", mpi_get_nbits (prime), mpi_get_nbits (q)); if (mode == 1) log_debug (", q0=%u", mpi_get_nbits (q_factor)); for (i = 0; i < n; i++) log_debug (", p%d=%u", i, mpi_get_nbits (factors[i])); progress('\n'); } if (ret_factors) { /* Caller wants the factors. */ factors_new = gcry_calloc (n + 4, sizeof (*factors_new)); if (! factors_new) { err = gpg_err_code_from_errno (errno); goto leave; } if (all_factors) { i = 0; factors_new[i++] = gcry_mpi_set_ui (NULL, 2); factors_new[i++] = mpi_copy (q); if (mode == 1) factors_new[i++] = mpi_copy (q_factor); for(j=0; j < n; j++) factors_new[i++] = mpi_copy (factors[j]); } else { i = 0; if (mode == 1) { factors_new[i++] = mpi_copy (q_factor); for (; i <= n; i++) factors_new[i] = mpi_copy (factors[i]); } else for (; i < n; i++ ) factors_new[i] = mpi_copy (factors[i]); } } if (g) { /* Create a generator (start with 3). */ gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); if (mode == 1) err = GPG_ERR_NOT_IMPLEMENTED; else { factors[n] = q; factors[n + 1] = mpi_alloc_set_ui (2); mpi_sub_ui (pmin1, prime, 1); mpi_set_ui (g, 2); do { mpi_add_ui (g, g, 1); if (DBG_CIPHER) { log_debug ("checking g:"); gcry_mpi_dump (g); log_printf ("\n"); } else progress('^'); for (i = 0; i < n + 2; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); /* No mpi_pow(), but it is okay to use this with mod prime. */ gcry_mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); } while (i < n + 2); mpi_free (factors[n+1]); mpi_free (tmp); mpi_free (b); mpi_free (pmin1); } } if (! DBG_CIPHER) progress ('\n'); leave: if (pool) { for(i = 0; i < m; i++) mpi_free (pool[i]); gcry_free (pool); } if (factors) gcry_free (factors); /* Factors are shallow copies. */ if (perms) gcry_free (perms); mpi_free (val_2); mpi_free (q); mpi_free (q_factor); if (! err) { *prime_generated = prime; if (ret_factors) *ret_factors = factors_new; } else { if (factors_new) { for (i = 0; factors_new[i]; i++) mpi_free (factors_new[i]); gcry_free (factors_new); } mpi_free (prime); } return err; }
/* What we test here is that we don't overwrite our args and that using thne same mpi for several args works. */ static int test_powm (void) { int b_int = 17; int e_int = 3; int m_int = 19; gcry_mpi_t base = gcry_mpi_set_ui (NULL, b_int); gcry_mpi_t exp = gcry_mpi_set_ui (NULL, e_int); gcry_mpi_t mod = gcry_mpi_set_ui (NULL, m_int); gcry_mpi_t res = gcry_mpi_new (0); gcry_mpi_powm (res, base, exp, mod); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using base for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (base, base, exp, mod); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using exp for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (exp, base, exp, mod); if (gcry_mpi_cmp (res, exp)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check using mod for the result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui (exp, e_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (mod, base, exp, mod); if (gcry_mpi_cmp (res, mod)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (exp, e_int)) die ("test_powm_ui failed for exp at %d\n", __LINE__); /* Now check base ^ base mod mod. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (res, base, base, mod); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check base ^ base mod mod with base as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (base, base, base, mod); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (mod, m_int)) die ("test_powm failed for mod at %d\n", __LINE__); /* Check base ^ base mod mod with mod as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (mod, base, base, mod); if (gcry_mpi_cmp (res, mod)) die ("test_powm failed at %d\n", __LINE__); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); /* Now check base ^ base mod base. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_powm (res, base, base, base); if (gcry_mpi_cmp_ui (base, b_int)) die ("test_powm failed for base at %d\n", __LINE__); /* Check base ^ base mod base with base as result. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_powm (base, base, base, base); if (gcry_mpi_cmp (res, base)) die ("test_powm failed at %d\n", __LINE__); /* Check for a case: base is negative and expo is even. */ gcry_mpi_set_ui (base, b_int); gcry_mpi_neg (base, base); gcry_mpi_set_ui (exp, e_int * 2); gcry_mpi_set_ui(mod, m_int); gcry_mpi_powm (res, base, exp, mod); /* Result should be positive and it's 7 = (-17)^6 mod 19. */ if (gcry_mpi_is_neg (res) || gcry_mpi_cmp_ui (res, 7)) { if (verbose) { fprintf (stderr, "is_neg: %d\n", gcry_mpi_is_neg (res)); fprintf (stderr, "mpi: "); gcry_mpi_dump (res); putc ('\n', stderr); } die ("test_powm failed for negative base at %d\n", __LINE__); } gcry_mpi_release (base); gcry_mpi_release (exp); gcry_mpi_release (mod); gcry_mpi_release (res); /* Fixme: We should add the rest of the cases of course. */ return 1; }
static gboolean response_open_session_aes (SecretSession *session, GVariant *response) { gconstpointer buffer; GVariant *argument; const gchar *sig; gsize n_buffer; gcry_mpi_t peer; gcry_error_t gcry; gpointer ikm; gsize n_ikm; sig = g_variant_get_type_string (response); g_return_val_if_fail (sig != NULL, FALSE); if (!g_str_equal (sig, "(vo)")) { g_warning ("invalid OpenSession() response from daemon with signature: %s", sig); return FALSE; } g_assert (session->path == NULL); g_variant_get (response, "(vo)", &argument, &session->path); buffer = g_variant_get_fixed_array (argument, &n_buffer, sizeof (guchar)); gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, buffer, n_buffer, NULL); g_return_val_if_fail (gcry == 0, FALSE); g_variant_unref (argument); #if 0 g_printerr (" lib publi: "); gcry_mpi_dump (session->publi); g_printerr ("\n lib peer: "); gcry_mpi_dump (peer); g_printerr ("\n"); #endif ikm = egg_dh_gen_secret (peer, session->privat, session->prime, &n_ikm); gcry_mpi_release (peer); #if 0 g_printerr (" lib ikm: %s\n", egg_hex_encode (ikm, n_ikm)); #endif if (ikm == NULL) { g_warning ("couldn't negotiate a valid AES session key"); g_free (session->path); session->path = NULL; return FALSE; } session->n_key = 16; session->key = egg_secure_alloc (session->n_key); if (!egg_hkdf_perform ("sha256", ikm, n_ikm, NULL, 0, NULL, 0, session->key, session->n_key)) g_return_val_if_reached (FALSE); egg_secure_free (ikm); session->algorithms = ALGORITHMS_AES; return TRUE; }