static int wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo, gnutls_direction_t direction, gnutls_pk_params_st * params) { int ret, result; /* only for RSA we invert the coefficient --pgp type */ if (algo != GNUTLS_PK_RSA) return 0; if (params->params[5] == NULL) params->params[5] = _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0])); if (params->params[5] == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } ret = 1; if (direction == GNUTLS_IMPORT) { /* calculate exp1 [6] and exp2 [7] */ _gnutls_mpi_release (¶ms->params[6]); _gnutls_mpi_release (¶ms->params[7]); result = _gnutls_calc_rsa_exp (params->params, RSA_PRIVATE_PARAMS); if (result < 0) { gnutls_assert (); return result; } ret = gcry_mpi_invm (params->params[5], params->params[3], params->params[4]); params->params_nr = RSA_PRIVATE_PARAMS; } else if (direction == GNUTLS_EXPORT) ret = gcry_mpi_invm (params->params[5], params->params[4], params->params[3]); if (ret == 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } return 0; }
void point_double(struct affine_point *p, const struct domain_params *dp) { if (gcry_mpi_cmp_ui(p->y, 0)) { gcry_mpi_t t1, t2; t1 = gcry_mpi_snew(0); t2 = gcry_mpi_snew(0); gcry_mpi_mulm(t2, p->x, p->x, dp->m); gcry_mpi_addm(t1, t2, t2, dp->m); gcry_mpi_addm(t1, t1, t2, dp->m); gcry_mpi_addm(t1, t1, dp->a, dp->m); gcry_mpi_addm(t2, p->y, p->y, dp->m); gcry_mpi_invm(t2, t2, dp->m); gcry_mpi_mulm(t1, t1, t2, dp->m); gcry_mpi_mulm(t2, t1, t1, dp->m); gcry_mpi_subm(t2, t2, p->x, dp->m); gcry_mpi_subm(t2, t2, p->x, dp->m); gcry_mpi_subm(p->x, p->x, t2, dp->m); gcry_mpi_mulm(t1, t1, p->x, dp->m); gcry_mpi_subm(p->y, t1, p->y, dp->m); gcry_mpi_set(p->x, t2); gcry_mpi_release(t1); gcry_mpi_release(t2); } else gcry_mpi_set_ui(p->x, 0); }
int ECDSA_verify(const char *msg, const struct affine_point *Q, const gcry_mpi_t sig, const struct curve_params *cp) { gcry_mpi_t e, r, s; struct affine_point X1, X2; int res = 0; r = gcry_mpi_new(0); s = gcry_mpi_new(0); gcry_mpi_div(s, r, sig, cp->dp.order, 0); if (gcry_mpi_cmp_ui(s, 0) <= 0 || gcry_mpi_cmp(s, cp->dp.order) >= 0 || gcry_mpi_cmp_ui(r, 0) <= 0 || gcry_mpi_cmp(r, cp->dp.order) >= 0) goto end; gcry_mpi_scan(&e, GCRYMPI_FMT_USG, msg, 64, NULL); gcry_mpi_mod(e, e, cp->dp.order); gcry_mpi_invm(s, s, cp->dp.order); gcry_mpi_mulm(e, e, s, cp->dp.order); X1 = pointmul(&cp->dp.base, e, &cp->dp); gcry_mpi_mulm(e, r, s, cp->dp.order); X2 = pointmul(Q, e, &cp->dp); point_add(&X1, &X2, &cp->dp); gcry_mpi_release(e); if (! point_is_zero(&X1)) { gcry_mpi_mod(s, X1.x, cp->dp.order); res = ! gcry_mpi_cmp(s, r); } point_release(&X1); point_release(&X2); end: gcry_mpi_release(r); gcry_mpi_release(s); return res; }
void point_add(struct affine_point *p1, const struct affine_point *p2, const struct domain_params *dp) { if (! point_is_zero(p2)) { if (! point_is_zero(p1)) { if (! gcry_mpi_cmp(p1->x, p2->x)) { if (! gcry_mpi_cmp(p1->y, p2->y)) point_double(p1, dp); else point_load_zero(p1); } else { gcry_mpi_t t; t = gcry_mpi_snew(0); gcry_mpi_subm(t, p1->y, p2->y, dp->m); gcry_mpi_subm(p1->y, p1->x, p2->x, dp->m); gcry_mpi_invm(p1->y, p1->y, dp->m); gcry_mpi_mulm(p1->y, t, p1->y, dp->m); gcry_mpi_mulm(t, p1->y, p1->y, dp->m); gcry_mpi_addm(p1->x, p1->x, p2->x, dp->m); gcry_mpi_subm(p1->x, t, p1->x, dp->m); gcry_mpi_subm(t, p2->x, p1->x, dp->m); gcry_mpi_mulm(p1->y, p1->y, t, dp->m); gcry_mpi_subm(p1->y, p1->y, p2->y, dp->m); gcry_mpi_release(t); } } else point_set(p1, p2); } }
/** * Unblind a blind-signed signature. The signature should have been generated * with #GNUNET_CRYPTO_rsa_sign() using a hash that was blinded with * #GNUNET_CRYPTO_rsa_blind(). * * @param sig the signature made on the blinded signature purpose * @param bkey the blinding key used to blind the signature purpose * @param pkey the public key of the signer * @return unblinded signature on success, NULL on error */ struct GNUNET_CRYPTO_rsa_Signature * GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_rsa_Signature *sig, struct GNUNET_CRYPTO_rsa_BlindingKey *bkey, struct GNUNET_CRYPTO_rsa_PublicKey *pkey) { gcry_mpi_t n; gcry_mpi_t s; gcry_mpi_t r_inv; gcry_mpi_t ubsig; int ret; struct GNUNET_CRYPTO_rsa_Signature *sret; ret = key_from_sexp (&n, pkey->sexp, "public-key", "n"); if (0 != ret) ret = key_from_sexp (&n, pkey->sexp, "rsa", "n"); if (0 != ret) { GNUNET_break_op (0); return NULL; } ret = key_from_sexp (&s, sig->sexp, "sig-val", "s"); if (0 != ret) ret = key_from_sexp (&s, sig->sexp, "rsa", "s"); if (0 != ret) { gcry_mpi_release (n); GNUNET_break_op (0); return NULL; } r_inv = gcry_mpi_new (0); if (1 != gcry_mpi_invm (r_inv, bkey->r, n)) { GNUNET_break_op (0); gcry_mpi_release (n); gcry_mpi_release (r_inv); gcry_mpi_release (s); return NULL; } ubsig = gcry_mpi_new (0); gcry_mpi_mulm (ubsig, s, r_inv, n); gcry_mpi_release (n); gcry_mpi_release (r_inv); gcry_mpi_release (s); sret = GNUNET_new (struct GNUNET_CRYPTO_rsa_Signature); GNUNET_assert (0 == gcry_sexp_build (&sret->sexp, NULL, "(sig-val (rsa (s %M)))", ubsig)); gcry_mpi_release (ubsig); return sret; }
unsigned char* inv(unsigned char* x, unsigned char* y){ size_t scanned; unsigned char *result; gcry_mpi_t a = gcry_mpi_new(0); gcry_mpi_t b = gcry_mpi_new(0); gcry_mpi_scan(&a, GCRYMPI_FMT_HEX, x, 0, &scanned); gcry_mpi_scan(&b, GCRYMPI_FMT_HEX, y, 0, &scanned); gcry_mpi_invm(a, a, b); gcry_mpi_aprint(GCRYMPI_FMT_HEX, &result, NULL, a); return result; }
int p2p_convert_private_key(RSA *key, gcry_sexp_t *r_key) { size_t err; char *buf; gcry_mpi_t n_mpi, e_mpi, d_mpi, p_mpi, q_mpi, u_mpi; buf = BN_bn2hex(key->n); gcry_mpi_scan(&n_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); buf = BN_bn2hex(key->e); gcry_mpi_scan(&e_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); buf = BN_bn2hex(key->d); gcry_mpi_scan(&d_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); buf = BN_bn2hex(key->p); gcry_mpi_scan(&p_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); buf = BN_bn2hex(key->q); gcry_mpi_scan(&q_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); buf = BN_bn2hex(key->iqmp); gcry_mpi_scan(&u_mpi, GCRYMPI_FMT_HEX, buf, 0, &err); OPENSSL_free(buf); if(gcry_mpi_cmp(p_mpi, q_mpi) > 0) { gcry_mpi_swap(p_mpi, q_mpi); gcry_mpi_invm(u_mpi, p_mpi, q_mpi); } gcry_sexp_build(r_key, &err, "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))", n_mpi, e_mpi, d_mpi, p_mpi, q_mpi, u_mpi); gcry_mpi_release(n_mpi); gcry_mpi_release(e_mpi); gcry_mpi_release(d_mpi); gcry_mpi_release(p_mpi); gcry_mpi_release(q_mpi); gcry_mpi_release(u_mpi); gcry_error_t sane = gcry_pk_testkey(*r_key); if(sane) { return -1; } return 0; }
/* Compose $(xp,xq) \in Z_p \times Z_q$ into $x \in Z_n$ using Chinese Remainder Theorem */ static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, const gcry_mpi_t p, const gcry_mpi_t q) { gcry_mpi_t a, u; a = gcry_mpi_new(0); u = gcry_mpi_new(0); *x = gcry_mpi_new(0); gcry_mpi_subm(a, xq, xp, q); gcry_mpi_invm(u, p, q); gcry_mpi_mulm(a, a, u, q); /* a = (xq - xp) / p (mod q) */ gcry_mpi_mul(*x, p, a); gcry_mpi_add(*x, *x, xp); /* x = p * ((xq - xp) / p mod q) + xp */ gcry_mpi_release(a); gcry_mpi_release(u); }
struct affine_point jacobian_to_affine(const struct jacobian_point *p, const struct domain_params *dp) { struct affine_point r = point_new(); if (gcry_mpi_cmp_ui(p->z, 0)) { gcry_mpi_t h; h = gcry_mpi_snew(0); gcry_mpi_invm(h, p->z, dp->m); gcry_mpi_mulm(r.y, h, h, dp->m); gcry_mpi_mulm(r.x, p->x, r.y, dp->m); gcry_mpi_mulm(r.y, r.y, h, dp->m); gcry_mpi_mulm(r.y, r.y, p->y, dp->m); gcry_mpi_release(h); } return r; }
/* Algorithms 4.29 and 4.30 in the "Guide to Elliptic Curve Cryptography" */ gcry_mpi_t ECDSA_sign(const char *msg, const gcry_mpi_t d, const struct curve_params *cp) { struct affine_point p1; gcry_mpi_t e, k, r, s; #if ECDSA_DETERMINISTIC struct aes256cprng *cprng; cprng = ecdsa_cprng_init(msg, d, cp); #endif r = gcry_mpi_snew(0); s = gcry_mpi_snew(0); Step1: #if ECDSA_DETERMINISTIC k = ecdsa_cprng_get_exponent(cprng, cp); #else k = get_random_exponent(cp); #endif p1 = pointmul(&cp->dp.base, k, &cp->dp); gcry_mpi_mod(r, p1.x, cp->dp.order); point_release(&p1); if (! gcry_mpi_cmp_ui(r, 0)) { gcry_mpi_release(k); goto Step1; } gcry_mpi_scan(&e, GCRYMPI_FMT_USG, msg, 64, NULL); gcry_mpi_set_flag(e, GCRYMPI_FLAG_SECURE); gcry_mpi_mod(e, e, cp->dp.order); gcry_mpi_mulm(s, d, r, cp->dp.order); gcry_mpi_addm(s, s, e, cp->dp.order); gcry_mpi_invm(e, k, cp->dp.order); gcry_mpi_mulm(s, s, e, cp->dp.order); gcry_mpi_release(e); gcry_mpi_release(k); if (! gcry_mpi_cmp_ui(s, 0)) goto Step1; gcry_mpi_mul(s, s, cp->dp.order); gcry_mpi_add(s, s, r); gcry_mpi_release(r); #if ECDSA_DETERMINISTIC ecdsa_cprng_done(cprng); #endif return s; }
void attack(int i, unsigned char *digest, int hash_len){ void* dsa_buf; gcry_sexp_t new_dsa_key_pair; gcry_sexp_t ciphertext , plaintext, ptx2, ctx2; gcry_sexp_t r_param, r_tilda_param; gcry_sexp_t s_param, s_tilda_param; gcry_sexp_t g_param; gcry_sexp_t p_param; gcry_sexp_t q_param; gcry_sexp_t m_param; gcry_sexp_t y_param; gcry_sexp_t x_param; gcry_sexp_t misc_param; gcry_error_t err; gcry_mpi_t msg_digest, m; gcry_mpi_t r , r_tilda; gcry_mpi_t s , s_tilda; gcry_mpi_t g; gcry_mpi_t p; gcry_mpi_t q; gcry_mpi_t y; gcry_mpi_t x; retrieve_key_pair(files[i]); //*************** CORRECT SIGNATURE ********************// //20 is the mdlen of sha1 as specified in https://lists.gnupg.org/pipermail/gnupg-devel/2013-September/027916.html //a well formatted number for the immaediate has an even number of digits err = gcry_sexp_build(&plaintext, NULL, "(data (flags rfc6979) (hash %s %b))" , "sha1", hash_len , digest); err = gcry_pk_sign(&ciphertext, plaintext, dsa_key_pair); //now let's convert the s-expression representing r into an MPI in order //to use it in the equation of the attack //--------- CIPHERTEXT -------------- //intercepted during some sniffing... r_param = gcry_sexp_find_token(ciphertext, "r", 0); r = gcry_sexp_nth_mpi ( r_param , 1, GCRYMPI_FMT_USG); s_param = gcry_sexp_find_token(ciphertext, "s", 0); s = gcry_sexp_nth_mpi ( s_param , 1, GCRYMPI_FMT_USG); //--------- PUB KEY -------------- g_param = gcry_sexp_find_token(dsa_key_pair, "g", 0); g = gcry_sexp_nth_mpi ( g_param , 1, GCRYMPI_FMT_USG); p_param = gcry_sexp_find_token(dsa_key_pair, "p", 0); p = gcry_sexp_nth_mpi ( p_param , 1, GCRYMPI_FMT_USG); q_param = gcry_sexp_find_token(dsa_key_pair, "q", 0); q = gcry_sexp_nth_mpi ( q_param , 1, GCRYMPI_FMT_USG); y_param = gcry_sexp_find_token(dsa_key_pair, "y", 0); y = gcry_sexp_nth_mpi ( y_param , 1, GCRYMPI_FMT_USG); x_param = gcry_sexp_find_token(dsa_key_pair, "x", 0); x = gcry_sexp_nth_mpi ( x_param , 1, GCRYMPI_FMT_USG); misc_param = gcry_sexp_find_token(dsa_key_pair, "misc-key-info", 0); //*************** FAULTY SIGNATURE ********************// err = gcry_sexp_build(&ptx2, NULL, "(data (flags rfc6979) (hash %s %b) (attack2_byte))" , "sha1", hash_len , digest); err = gcry_pk_sign(&ctx2, ptx2, dsa_key_pair); s_tilda_param = gcry_sexp_find_token(ctx2, "s", 0); s_tilda = gcry_sexp_nth_mpi ( s_tilda_param , 1, GCRYMPI_FMT_USG); r_tilda_param = gcry_sexp_find_token(ctx2, "r", 0); r_tilda = gcry_sexp_nth_mpi ( r_tilda_param , 1, GCRYMPI_FMT_USG); m_param = gcry_sexp_find_token(ptx2, "hash", 0); m = gcry_sexp_nth_mpi ( m_param , 2, GCRYMPI_FMT_USG); //NOW LET'S START THE ATTACK unsigned long e = 0; unsigned int qbits = mpi_get_nbits(q); unsigned int pbits = mpi_get_nbits(p); int hash_len_bits = hash_len*8; gcry_mpi_t one = gcry_mpi_set_ui(NULL, 1); gcry_mpi_t tmp = gcry_mpi_new(qbits); gcry_mpi_t result = gcry_mpi_new(mpi_get_nbits(s)); gcry_mpi_invm(r,r,q); // r^-1 unsigned int j; for(e = 0; e < qbits ; e++){ gcry_mpi_t empi = gcry_mpi_set_ui(NULL,e); gcry_mpi_t twoi = gcry_mpi_new(e); gcry_mpi_mul_2exp(empi, one, e); // twoi = 2^e for( j=0; j< 256 ; j++){ gcry_mpi_t jmpi = gcry_mpi_set_ui(NULL,j); gcry_mpi_mulm(twoi,jmpi,empi,q); //retrieve k gcry_mpi_mulm(tmp, s_tilda, twoi, q); // s_tilda*(2^e) modq q gcry_mpi_subm(result, s_tilda, s, q); // s_tilda - s mod q gcry_mpi_invm(result, result, q); // (s_tilda - s mod q)^-1 gcry_mpi_mulm(result,result, tmp, q); // s_tilda*(2^3) mod q)*(s_tilda - s mod q)^-1 === k //retrieve x gcry_mpi_mulm(result, s, result,q); // s*k mod q gcry_mpi_subm(result, result, m, q); // s*k - m mod q gcry_mpi_mulm(result, result,r,q); //(s*k -m)*r^-1 mod q err = gcry_sexp_build(&new_dsa_key_pair,NULL, "(key-data" " (public-key" " (dsa(p%m)(q%m)(g%m)(y%m)))" " (private-key" " (dsa(p%m)(q%m)(g%m)(y%m)(x%m))))", p,q,g,y,p,q,g,y,result); err = gcry_pk_sign(&ctx2, plaintext, new_dsa_key_pair); err = gcry_pk_verify(ctx2, plaintext, dsa_key_pair); if (err) { //puts("gcrypt: verify failed"); continue; } else{ printf("\n[!!!]PRIVATE KEY %d %d BITS CRACKED!!\n" , pbits,qbits ); printf("[DBG] BYTE : %d * 2^%d FAULT: k-j*2^%d\n" , j , (int)e,(int)e); //DEBUG DEBUG_MPI_PRINT(result,"X = "); printf("\n"); return; } } } for(e = 0; e < qbits; e++){ gcry_mpi_t empi = gcry_mpi_set_ui(NULL,e); gcry_mpi_t twoi = gcry_mpi_new(e); gcry_mpi_mul_2exp(empi, one, e); // twoi = 2^e for( j=0; j< 256 ; j++){ gcry_mpi_t jmpi = gcry_mpi_set_ui(NULL,j); gcry_mpi_mulm(twoi,jmpi,empi,q); //retrieve k gcry_mpi_mulm(tmp, s_tilda, twoi, q); // s_tilda*(2^e) modq q gcry_mpi_subm(result, s, s_tilda, q); // s_tilda - s mod q gcry_mpi_invm(result, result, q); // (s_tilda - s mod q)^-1 gcry_mpi_mulm(result,result, tmp, q); // s_tilda*(2^3) mod q)*(s_tilda - s mod q)^-1 === k //retrieve x gcry_mpi_mulm(result, s, result,q); // s*k mod q gcry_mpi_subm(result, result, m, q); // s*k - m mod q gcry_mpi_mulm(result, result,r,q); //(s*k -m)*r^-1 mod q err = gcry_sexp_build(&new_dsa_key_pair,NULL, "(key-data" " (public-key" " (dsa(p%m)(q%m)(g%m)(y%m)))" " (private-key" " (dsa(p%m)(q%m)(g%m)(y%m)(x%m))))", p,q,g,y,p,q,g,y,result); err = gcry_pk_sign(&ctx2, plaintext, new_dsa_key_pair); err = gcry_pk_verify(ctx2, plaintext, dsa_key_pair); if (err) { continue; } else{ printf("\n[!!!]PRIVATE KEY %d %d BITS CRACKED!!\n" , pbits,qbits ); printf("[DBG] BYTE : %d * 2^%d FAULT: k+j*2^%d\n" , j , (int)e,(int)e); //DEBUG DEBUG_MPI_PRINT(result,"X = "); printf("\n"); return; } } } }
/** * Generate a key pair with a key of size NBITS. * @param sk where to store the key * @param nbits the number of bits to use * @param hc the HC to use for PRNG (modified!) */ static void generate_kblock_key (KBlock_secret_key *sk, unsigned int nbits, struct GNUNET_HashCode * hc) { gcry_mpi_t t1, t2; gcry_mpi_t phi; /* helper: (p-1)(q-1) */ gcry_mpi_t g; gcry_mpi_t f; /* make sure that nbits is even so that we generate p, q of equal size */ if ((nbits & 1)) nbits++; sk->e = gcry_mpi_set_ui (NULL, 257); sk->n = gcry_mpi_new (0); sk->p = gcry_mpi_new (0); sk->q = gcry_mpi_new (0); sk->d = gcry_mpi_new (0); sk->u = gcry_mpi_new (0); t1 = gcry_mpi_new (0); t2 = gcry_mpi_new (0); phi = gcry_mpi_new (0); g = gcry_mpi_new (0); f = gcry_mpi_new (0); do { do { gcry_mpi_release (sk->p); gcry_mpi_release (sk->q); gen_prime (&sk->p, nbits / 2, hc); gen_prime (&sk->q, nbits / 2, hc); if (gcry_mpi_cmp (sk->p, sk->q) > 0) /* p shall be smaller than q (for calc of u) */ gcry_mpi_swap (sk->p, sk->q); /* calculate the modulus */ gcry_mpi_mul (sk->n, sk->p, sk->q); } while (gcry_mpi_get_nbits (sk->n) != nbits); /* calculate Euler totient: phi = (p-1)(q-1) */ gcry_mpi_sub_ui (t1, sk->p, 1); gcry_mpi_sub_ui (t2, sk->q, 1); gcry_mpi_mul (phi, t1, t2); gcry_mpi_gcd (g, t1, t2); gcry_mpi_div (f, NULL, phi, g, 0); while (0 == gcry_mpi_gcd (t1, sk->e, phi)) { /* (while gcd is not 1) */ gcry_mpi_add_ui (sk->e, sk->e, 2); } /* calculate the secret key d = e^1 mod phi */ } while ((0 == gcry_mpi_invm (sk->d, sk->e, f)) || (0 == gcry_mpi_invm (sk->u, sk->p, sk->q))); gcry_mpi_release (t1); gcry_mpi_release (t2); gcry_mpi_release (phi); gcry_mpi_release (f); gcry_mpi_release (g); }
/* Check that the RSA secret key SKEY is valid. Swap parameters to the libgcrypt standard. */ static gpg_error_t rsa_key_check (struct rsa_secret_key_s *skey) { int err = 0; gcry_mpi_t t = gcry_mpi_snew (0); gcry_mpi_t t1 = gcry_mpi_snew (0); gcry_mpi_t t2 = gcry_mpi_snew (0); gcry_mpi_t phi = gcry_mpi_snew (0); /* Check that n == p * q. */ gcry_mpi_mul (t, skey->p, skey->q); if (gcry_mpi_cmp( t, skey->n) ) { log_error ("RSA oops: n != p * q\n"); err++; } /* Check that p is less than q. */ if (gcry_mpi_cmp (skey->p, skey->q) > 0) { gcry_mpi_t tmp; log_info ("swapping secret primes\n"); tmp = gcry_mpi_copy (skey->p); gcry_mpi_set (skey->p, skey->q); gcry_mpi_set (skey->q, tmp); gcry_mpi_release (tmp); /* Recompute u. */ gcry_mpi_invm (skey->u, skey->p, skey->q); } /* Check that e divides neither p-1 nor q-1. */ gcry_mpi_sub_ui (t, skey->p, 1 ); gcry_mpi_div (NULL, t, t, skey->e, 0); if (!gcry_mpi_cmp_ui( t, 0) ) { log_error ("RSA oops: e divides p-1\n"); err++; } gcry_mpi_sub_ui (t, skey->q, 1); gcry_mpi_div (NULL, t, t, skey->e, 0); if (!gcry_mpi_cmp_ui( t, 0)) { log_info ("RSA oops: e divides q-1\n" ); err++; } /* Check that d is correct. */ gcry_mpi_sub_ui (t1, skey->p, 1); gcry_mpi_sub_ui (t2, skey->q, 1); gcry_mpi_mul (phi, t1, t2); gcry_mpi_invm (t, skey->e, phi); if (gcry_mpi_cmp (t, skey->d)) { /* No: try universal exponent. */ gcry_mpi_gcd (t, t1, t2); gcry_mpi_div (t, NULL, phi, t, 0); gcry_mpi_invm (t, skey->e, t); if (gcry_mpi_cmp (t, skey->d)) { log_error ("RSA oops: bad secret exponent\n"); err++; } } /* Check for correctness of u. */ gcry_mpi_invm (t, skey->p, skey->q); if (gcry_mpi_cmp (t, skey->u)) { log_info ("RSA oops: bad u parameter\n"); err++; } if (err) log_info ("RSA secret key check failed\n"); gcry_mpi_release (t); gcry_mpi_release (t1); gcry_mpi_release (t2); gcry_mpi_release (phi); return err? gpg_error (GPG_ERR_BAD_SECKEY):0; }
/* Compute and print missing RSA parameters. */ static void compute_missing (gcry_mpi_t rsa_p, gcry_mpi_t rsa_q, gcry_mpi_t rsa_e) { gcry_mpi_t rsa_n, rsa_d, rsa_pm1, rsa_qm1, rsa_u; gcry_mpi_t phi, tmp_g, tmp_f; rsa_n = gcry_mpi_new (0); rsa_d = gcry_mpi_new (0); rsa_pm1 = gcry_mpi_new (0); rsa_qm1 = gcry_mpi_new (0); rsa_u = gcry_mpi_new (0); phi = gcry_mpi_new (0); tmp_f = gcry_mpi_new (0); tmp_g = gcry_mpi_new (0); /* Check that p < q; if not swap p and q. */ if (openpgp_mode && gcry_mpi_cmp (rsa_p, rsa_q) > 0) { fprintf (stderr, PGM ": swapping p and q\n"); gcry_mpi_swap (rsa_p, rsa_q); } gcry_mpi_mul (rsa_n, rsa_p, rsa_q); /* Compute the Euler totient: phi = (p-1)(q-1) */ gcry_mpi_sub_ui (rsa_pm1, rsa_p, 1); gcry_mpi_sub_ui (rsa_qm1, rsa_q, 1); gcry_mpi_mul (phi, rsa_pm1, rsa_qm1); if (!gcry_mpi_gcd (tmp_g, rsa_e, phi)) die ("parameter 'e' does match 'p' and 'q'\n"); /* Compute: f = lcm(p-1,q-1) = phi / gcd(p-1,q-1) */ gcry_mpi_gcd (tmp_g, rsa_pm1, rsa_qm1); gcry_mpi_div (tmp_f, NULL, phi, tmp_g, -1); /* Compute the secret key: d = e^{-1} mod lcm(p-1,q-1) */ gcry_mpi_invm (rsa_d, rsa_e, tmp_f); /* Compute the CRT helpers: d mod (p-1), d mod (q-1) */ gcry_mpi_mod (rsa_pm1, rsa_d, rsa_pm1); gcry_mpi_mod (rsa_qm1, rsa_d, rsa_qm1); /* Compute the CRT value: OpenPGP: u = p^{-1} mod q Standard: iqmp = q^{-1} mod p */ if (openpgp_mode) gcry_mpi_invm (rsa_u, rsa_p, rsa_q); else gcry_mpi_invm (rsa_u, rsa_q, rsa_p); gcry_mpi_release (phi); gcry_mpi_release (tmp_f); gcry_mpi_release (tmp_g); /* Print everything. */ print_mpi_line ("n", rsa_n); print_mpi_line ("e", rsa_e); if (openpgp_mode) print_mpi_line ("d", rsa_d); print_mpi_line ("p", rsa_p); print_mpi_line ("q", rsa_q); if (openpgp_mode) print_mpi_line ("u", rsa_u); else { print_mpi_line ("dmp1", rsa_pm1); print_mpi_line ("dmq1", rsa_qm1); print_mpi_line ("iqmp", rsa_u); } gcry_mpi_release (rsa_n); gcry_mpi_release (rsa_d); gcry_mpi_release (rsa_pm1); gcry_mpi_release (rsa_qm1); gcry_mpi_release (rsa_u); }
/* * Parse the DER-encoded data at ps_data_der * saving the key in an S-expression */ int RSAKey::readDER( unsigned char const* ps_data_der, size_t length ) { struct tag_info tag_inf; gcry_mpi_t key_params[8]; gcry_error_t err; int i; /* parse the ASN1 structure */ if( parseTag( &ps_data_der, &length, &tag_inf ) || tag_inf.tag != TAG_SEQUENCE || tag_inf.class_ || !tag_inf.cons || tag_inf.ndef ) goto bad_asn1; if( parseTag( &ps_data_der, &length, &tag_inf ) || tag_inf.tag != TAG_INTEGER || tag_inf.class_ || tag_inf.cons || tag_inf.ndef ) goto bad_asn1; if( tag_inf.length != 1 || *ps_data_der ) goto bad_asn1; /* The value of the first integer is no 0. */ ps_data_der += tag_inf.length; length -= tag_inf.length; for( i = 0; i < 8; i++ ) { if( parseTag( &ps_data_der, &length, &tag_inf ) || tag_inf.tag != TAG_INTEGER || tag_inf.class_ || tag_inf.cons || tag_inf.ndef ) goto bad_asn1; err = gcry_mpi_scan( key_params + i, GCRYMPI_FMT_USG, ps_data_der, tag_inf.length, NULL ); if( err ) { msg_Err( this->p_demux, "error scanning RSA parameter %d: %s", i, gpg_strerror( err ) ); goto error; } ps_data_der += tag_inf.length; length -= tag_inf.length; } /* Convert from OpenSSL parameter ordering to the OpenPGP order. * First check that p < q; if not swap p and q and recompute u. */ if( gcry_mpi_cmp( key_params[3], key_params[4] ) > 0 ) { gcry_mpi_swap( key_params[3], key_params[4] ); gcry_mpi_invm( key_params[7], key_params[3], key_params[4] ); } /* Build the S-expression. */ err = gcry_sexp_build( & this->priv_key, NULL, "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", key_params[0], key_params[1], key_params[2], key_params[3], key_params[4], key_params[7] ); if( err ) { msg_Err( this->p_demux, "error building S-expression: %s", gpg_strerror( err ) ); goto error; } /* clear data */ for( i = 0; i < 8; i++ ) gcry_mpi_release( key_params[i] ); return VLC_SUCCESS; bad_asn1: msg_Err( this->p_demux, "could not parse ASN1 structure; key might be corrupted" ); error: for( i = 0; i < 8; i++ ) gcry_mpi_release( key_params[i] ); return VLC_EGENERIC; }
void attack(int i, unsigned char *digest, int hash_len){ gcry_error_t err; gcry_sexp_t ciphertext , plaintext, ptx2, new_dsa_key_pair; gcry_sexp_t r_param, r_tilda_param, k_tilda_param, msg_digest_param; gcry_sexp_t s_param, s_tilda_param; gcry_sexp_t g_param; gcry_sexp_t p_param; gcry_sexp_t q_param; gcry_sexp_t x_param, y_param; gcry_mpi_t r , r_tilda, k_tilda, x, y; gcry_mpi_t s , s_tilda; gcry_mpi_t g; gcry_mpi_t p; gcry_mpi_t q; gcry_mpi_t msg_digest; retrieve_key_pair(files[i]); //*************** CORRECT SIGNATURE ********************// //20 is the mdlen of sha1 as specified in https://lists.gnupg.org/pipermail/gnupg-devel/2013-September/027916.html //a well formatted number for the immaediate has an even number of digits err = gcry_sexp_build(&plaintext, NULL, "(data (flags rfc6979) (hash %s %b))" , "sha1", hash_len , digest); err = gcry_pk_sign(&ciphertext, plaintext, dsa_key_pair); //now let's convert the s-expression representing r into an MPI in order //to use it in the equation of the attack //--------- CIPHERTEXT -------------- r_param = gcry_sexp_find_token(ciphertext, "r", 0); r = gcry_sexp_nth_mpi ( r_param , 1, GCRYMPI_FMT_USG); s_param = gcry_sexp_find_token(ciphertext, "s", 0); s = gcry_sexp_nth_mpi ( s_param , 1, GCRYMPI_FMT_USG); //--------- PUB KEY -------------- g_param = gcry_sexp_find_token(dsa_key_pair, "g", 0); g = gcry_sexp_nth_mpi ( g_param , 1, GCRYMPI_FMT_USG); p_param = gcry_sexp_find_token(dsa_key_pair, "p", 0); p = gcry_sexp_nth_mpi ( p_param , 1, GCRYMPI_FMT_USG); q_param = gcry_sexp_find_token(dsa_key_pair, "q", 0); q = gcry_sexp_nth_mpi ( q_param , 1, GCRYMPI_FMT_USG); x_param = gcry_sexp_find_token(dsa_key_pair, "x", 0); x = gcry_sexp_nth_mpi ( x_param , 1, GCRYMPI_FMT_USG); y_param = gcry_sexp_find_token(dsa_key_pair, "y", 0); y = gcry_sexp_nth_mpi ( y_param , 1, GCRYMPI_FMT_USG); unsigned int qbits = mpi_get_nbits(q); unsigned int pbits = mpi_get_nbits(p); msg_digest_param = gcry_sexp_find_token(plaintext, "hash", 0); msg_digest = gcry_sexp_nth_mpi ( msg_digest_param , 2, GCRYMPI_FMT_USG); //*************** FAULTY SIGNATURE ********************// err = gcry_sexp_build(&ptx2, NULL, "(data (flags rfc6979) (hash %s %b) (attack))" , "sha1", hash_len , digest); err = gcry_pk_sign(&ciphertext, ptx2, dsa_key_pair); s_tilda_param = gcry_sexp_find_token(ciphertext, "s", 0); s_tilda = gcry_sexp_nth_mpi ( s_tilda_param , 1, GCRYMPI_FMT_USG); r_tilda_param = gcry_sexp_find_token(ciphertext, "r", 0); r_tilda = gcry_sexp_nth_mpi ( r_tilda_param , 1, GCRYMPI_FMT_USG); k_tilda_param = gcry_sexp_find_token(ciphertext, "k", 0); k_tilda = gcry_sexp_nth_mpi ( k_tilda_param , 1, GCRYMPI_FMT_USG); //POC // 1 - choose a message // 2 - do the correct sign and obtain s and r // 3 - do the faulty sign and obtain s_tilda and r_tilda gcry_mpi_t tmp = gcry_mpi_new(mpi_get_nbits(p)); gcry_mpi_t result = gcry_mpi_new(mpi_get_nbits(p)); gcry_mpi_subm(tmp, s_tilda, s,q); //s-tilda -s mod q gcry_mpi_mulm(msg_digest, msg_digest, tmp, q); //m* (s-tilda -s mod q) mod q gcry_mpi_mulm(tmp, r_tilda, s, q); //r_tilda - s mod q gcry_mpi_mulm(result, s_tilda, r, q); //s_tilda - r mod q gcry_mpi_subm(result, tmp, result, q); //(r_tilda - s mod q) - (s_tilda - r mod q) mod q gcry_mpi_invm(result,result,q); //((r_tilda - s mod q) - (s_tilda - r mod q) mod q)^-1 mod q gcry_mpi_mulm(result, msg_digest, result, q); //( (m* (s-tilda -s mod q) mod q) * ((r_tilda - s mod q) - (s_tilda - r mod q) mod q)^-1 mod q ) mod q == x (private key) err = gcry_sexp_build(&new_dsa_key_pair,NULL, "(key-data" " (public-key" " (dsa(p%m)(q%m)(g%m)(y%m)))" " (private-key" " (dsa(p%m)(q%m)(g%m)(y%m)(x%m))))", p,q,g,y,p,q,g,y,result); err = gcry_pk_sign(&ciphertext, plaintext, new_dsa_key_pair); err = gcry_pk_verify(ciphertext, plaintext, dsa_key_pair); if (err) { printf("\nSomething went wrong...\n"); exit(0); } if(!printed){ DEBUG_MPI_PRINT(result,"\nX = "); printed = 1; } }
GkmDataResult gkm_data_der_read_private_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key) { GkmDataResult ret = GKM_DATA_UNRECOGNIZED; gcry_mpi_t n, e, d, p, q, u; gcry_mpi_t tmp; gulong version; GNode *asn = NULL; int res; n = e = d = p = q = u = NULL; asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data); if (!asn) goto done; ret = GKM_DATA_FAILURE; if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version)) goto done; /* We only support simple version */ if (version != 0) { ret = GKM_DATA_UNRECOGNIZED; g_message ("unsupported version of RSA key: %lu", version); goto done; } if (!gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "modulus", NULL), &n) || !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "publicExponent", NULL), &e) || !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "privateExponent", NULL), &d) || !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime1", NULL), &p) || !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "prime2", NULL), &q) || !gkm_data_asn1_read_mpi (egg_asn1x_node (asn, "coefficient", NULL), &u)) goto done; /* Fix up the incoming key so gcrypt likes it */ if (gcry_mpi_cmp (p, q) > 0) { /* P shall be smaller then Q! Swap primes. iqmp becomes u. */ tmp = p; p = q; q = tmp; } else { /* U needs to be recomputed. */ gcry_mpi_invm (u, p, q); } res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_RSA, n, e, d, p, q, u); if (res) goto done; g_assert (*s_key); ret = GKM_DATA_SUCCESS; done: egg_asn1x_destroy (asn); gcry_mpi_release (n); gcry_mpi_release (e); gcry_mpi_release (d); gcry_mpi_release (p); gcry_mpi_release (q); gcry_mpi_release (u); if (ret == GKM_DATA_FAILURE) g_message ("invalid RSA key"); return ret; }