/* * Perform the verification step [RFC3447 sec 8.2.2]. */ static int RSA_verify_signature(const struct public_key *key, const struct public_key_signature *sig) { size_t tsize; int ret; /* Variables as per RFC3447 sec 8.2.2 */ const u8 *H = sig->digest; u8 *EM = NULL; MPI m = NULL; size_t k; kenter(""); if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) return -ENOTSUPP; /* (1) Check the signature size against the public key modulus size */ k = mpi_get_nbits(key->rsa.n); tsize = mpi_get_nbits(sig->rsa.s); /* According to RFC 4880 sec 3.2, length of MPI is computed starting * from most significant bit. So the RFC 3447 sec 8.2.2 size check * must be relaxed to conform with shorter signatures - so we fail here * only if signature length is longer than modulus size. */ pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); if (k < tsize) { ret = -EBADMSG; goto error; } /* Round up and convert to octets */ k = (k + 7) / 8; /* (2b) Apply the RSAVP1 verification primitive to the public key */ ret = RSAVP1(key, sig->rsa.s, &m); if (ret < 0) goto error; /* (2c) Convert the message representative (m) to an encoded message * (EM) of length k octets. * * NOTE! The leading zero byte is suppressed by MPI, so we pass a * pointer to the _preceding_ byte to RSA_verify()! */ ret = RSA_I2OSP(m, k, &EM); if (ret < 0) goto error; ret = RSA_verify(H, EM - 1, k, sig->digest_size, RSA_ASN1_templates[sig->pkey_hash_algo].data, RSA_ASN1_templates[sig->pkey_hash_algo].size); error: kfree(EM); mpi_free(m); kleave(" = %d", ret); return ret; }
/**************** * print an MPI to the given stream and return the number of characters * printed. */ int mpi_print( FILE *fp, MPI a, int mode ) { int i, n=0; if( a == NULL ) return fprintf(fp, "[MPI_NULL]"); if( !mode ) { unsigned int n1; n1 = mpi_get_nbits(a); n += fprintf(fp, "[%u bits]", n1); } else { if( a->sign ) putc('-', fp); #if BYTES_PER_MPI_LIMB == 2 #define X "4" #elif BYTES_PER_MPI_LIMB == 4 #define X "8" #elif BYTES_PER_MPI_LIMB == 8 #define X "16" #else #error please define the format here #endif for(i=a->nlimbs; i > 0 ; i-- ) { n += fprintf(fp, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]); #undef X } if( !a->nlimbs ) putc('0', fp ); } return n; }
KBNODE make_mpi_comment_node( const char *s, gcry_mpi_t a ) { PACKET *pkt; byte *buf, *pp; size_t n1, nb1; size_t n = strlen(s); nb1 = mpi_get_nbits( a ); if (gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &n1, a)) BUG (); /* fixme: allocate it on the stack */ buf = xmalloc (n1); if (gcry_mpi_print (GCRYMPI_FMT_PGP, buf, n1, &n1, a)) BUG (); pkt = xcalloc (1, sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = xmalloc ( sizeof *pkt->pkt.comment + n + 2 + n1 ); pkt->pkt.comment->len = n+1+2+n1; pp = pkt->pkt.comment->data; memcpy(pp, s, n+1); memcpy(pp+n+1, buf, n1 ); xfree (buf); return new_kbnode( pkt ); }
/* * Integer to Octet String conversion [RFC3447 sec 4.1] */ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) { unsigned X_size, x_size; int X_sign; u8 *X; /* Make sure the string is the right length. The number should begin * with { 0x00, 0x01, ... } so we have to account for 15 leading zero * bits not being reported by MPI. */ x_size = mpi_get_nbits(x); pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); if (x_size != xLen * 8 - 15) return -ERANGE; X = mpi_get_buffer(x, &X_size, &X_sign); if (!X) return -ENOMEM; if (X_sign < 0) { kfree(X); return -EBADMSG; } if (X_size != xLen - 1) { kfree(X); return -EBADMSG; } *_X = X; return 0; }
unsigned int _gcry_elg_get_nbits (int algo, gcry_mpi_t *pkey) { (void)algo; return mpi_get_nbits (pkey[0]); }
unsigned int elg_get_nbits( int algo, MPI *pkey ) { if( !is_ELGAMAL(algo) ) return 0; return mpi_get_nbits( pkey[0] ); }
static unsigned int ecc_get_nbits (int algo, gcry_mpi_t *pkey) { (void)algo; return mpi_get_nbits (pkey[0]); }
/* RESULT must have been initialized and is set on success to the point given by VALUE. */ static gcry_error_t os2ec (mpi_point_t *result, gcry_mpi_t value) { gcry_error_t err; size_t n; unsigned char *buf; gcry_mpi_t x, y; n = (mpi_get_nbits (value)+7)/8; buf = gcry_xmalloc (n); err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value); if (err) { gcry_free (buf); return err; } if (n < 1) { gcry_free (buf); return GPG_ERR_INV_OBJ; } if (*buf != 4) { gcry_free (buf); return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ } if ( ((n-1)%2) ) { gcry_free (buf); return GPG_ERR_INV_OBJ; } n = (n-1)/2; err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); if (err) { gcry_free (buf); return err; } err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); gcry_free (buf); if (err) { mpi_free (x); return err; } mpi_set (result->x, x); mpi_set (result->y, y); mpi_set_ui (result->z, 1); mpi_free (x); mpi_free (y); return 0; }
static void print_key_data( PKT_public_key *pk, u32 *keyid ) { int n = pk ? pubkey_get_npkey( pk->pubkey_algo ) : 0; int i; for(i=0; i < n; i++ ) { printf("pkd:%d:%u:", i, mpi_get_nbits( pk->pkey[i] ) ); mpi_print(stdout, pk->pkey[i], 1 ); putchar(':'); putchar('\n'); } }
static void do_nbits (void) { unsigned int n; if (stackidx < 1) { fputs ("stack underflow\n", stderr); return; } n = mpi_get_nbits (stack[stackidx - 1]); mpi_set_ui (stack[stackidx - 1], n); }
/**************** * Get the number of nbits from the public key */ unsigned pubkey_nbits( int algo, MPI *pkey ) { int i; do { for(i=0; pubkey_table[i].name; i++ ) if( pubkey_table[i].algo == algo ) return (*pubkey_table[i].get_nbits)( algo, pkey ); } while( load_pubkey_modules() ); if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */ return mpi_get_nbits( pkey[0] ); return 0; }
/* This function is useful for v4 fingerprints and v3 or v4 key signing. */ void hash_public_key( MD_HANDLE md, PKT_public_key *pk ) { unsigned n=6; unsigned nb[PUBKEY_MAX_NPKEY]; unsigned nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; int npkey = pubkey_get_npkey( pk->pubkey_algo ); /* Two extra bytes for the expiration date in v3 */ if(pk->version<4) n+=2; if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0])) { pp[0]=mpi_get_opaque(pk->pkey[0],&nn[0]); n+=nn[0]; } else for(i=0; i < npkey; i++ ) { nb[i] = mpi_get_nbits(pk->pkey[i]); pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL ); n += 2 + nn[i]; } md_putc( md, 0x99 ); /* ctb */ /* What does it mean if n is greater than than 0xFFFF ? */ md_putc( md, n >> 8 ); /* 2 byte length header */ md_putc( md, n ); md_putc( md, pk->version ); md_putc( md, pk->timestamp >> 24 ); md_putc( md, pk->timestamp >> 16 ); md_putc( md, pk->timestamp >> 8 ); md_putc( md, pk->timestamp ); if(pk->version<4) { u16 days=0; if(pk->expiredate) days=(u16)((pk->expiredate - pk->timestamp) / 86400L); md_putc( md, days >> 8 ); md_putc( md, days ); }
/* Generate a random secret scalar k with an order of p At the beginning this was identical to the code is in elgamal.c. Later imporved by mmr. Further simplified by wk. */ static gcry_mpi_t gen_k (gcry_mpi_t p, int security_level) { gcry_mpi_t k; unsigned int nbits; nbits = mpi_get_nbits (p); k = mpi_snew (nbits); if (DBG_CIPHER) log_debug ("choosing a random k of %u bits\n", nbits); gcry_mpi_randomize (k, nbits, security_level); mpi_mod (k, k, p); /* k = k mod p */ return k; }
static void ksign_calc_pk_keyid(struct shash_desc *digest, struct ksign_public_key *pk) { unsigned n; unsigned nb[DSA_NPKEY]; unsigned nn[DSA_NPKEY]; uint8_t *pp[DSA_NPKEY]; uint32_t a32; int i; int npkey = DSA_NPKEY; n = pk->version < 4 ? 8 : 6; for (i = 0; i < npkey; i++) { nb[i] = mpi_get_nbits(pk->pkey[i]); pp[i] = mpi_get_buffer( pk->pkey[i], nn + i, NULL); n += 2 + nn[i]; } SHA1_putc(digest, 0x99); /* ctb */ SHA1_putc(digest, n >> 8); /* 2 uint8_t length header */ SHA1_putc(digest, n); if (pk->version < 4) SHA1_putc(digest, 3); else SHA1_putc(digest, 4); a32 = pk->timestamp; SHA1_putc(digest, a32 >> 24 ); SHA1_putc(digest, a32 >> 16 ); SHA1_putc(digest, a32 >> 8 ); SHA1_putc(digest, a32 >> 0 ); if (pk->version < 4) { uint16_t a16; if( pk->expiredate ) a16 = (uint16_t) ((pk->expiredate - pk->timestamp) / 86400L); else a16 = 0; SHA1_putc(digest, a16 >> 8); SHA1_putc(digest, a16 >> 0); }
/**************** * write an mpi to out. */ int mpi_write( IOBUF out, MPI a ) { int rc; unsigned nbits = mpi_get_nbits(a); byte *p, *buf; unsigned n; if( nbits > MAX_EXTERN_MPI_BITS ) log_bug("mpi_encode: mpi too large (%u bits)\n", nbits); iobuf_put(out, (nbits >>8) ); iobuf_put(out, (nbits) ); p = buf = mpi_get_buffer( a, &n, NULL ); rc = iobuf_write( out, p, n ); xfree(buf); return rc; }
static MD_HANDLE do_fingerprint_md( PKT_public_key *pk ) { MD_HANDLE md; unsigned n; unsigned nb[PUBKEY_MAX_NPKEY]; unsigned nn[PUBKEY_MAX_NPKEY]; byte *pp[PUBKEY_MAX_NPKEY]; int i; int npkey = pubkey_get_npkey( pk->pubkey_algo ); md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0); n = pk->version < 4 ? 8 : 6; for(i=0; i < npkey; i++ ) { nb[i] = mpi_get_nbits(pk->pkey[i]); pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL ); n += 2 + nn[i]; } md_putc( md, 0x99 ); /* ctb */ md_putc( md, n >> 8 ); /* 2 byte length header */ md_putc( md, n ); if( pk->version < 4 ) md_putc( md, 3 ); else md_putc( md, 4 ); { u32 a = pk->timestamp; md_putc( md, a >> 24 ); md_putc( md, a >> 16 ); md_putc( md, a >> 8 ); md_putc( md, a ); } if( pk->version < 4 ) { u16 a; if( pk->expiredate ) a = (u16)((pk->expiredate - pk->timestamp) / 86400L); else a = 0; md_putc( md, a >> 8 ); md_putc( md, a ); }
/**************** * print an MPI to the given buffer and return the number of characters * printed. */ int mpi_sprint( char* buffer, MPI a, int mode ) { int i, n=0; if( a == MPI_NULL ) return sprintf(buffer, "[MPI_NULL]"); if( !mode ) { unsigned int n1; n1 = mpi_get_nbits(a); n += sprintf(buffer, "[%u bits]", n1); } else { if( a->sign ) { buffer[0] = '-'; n++; } #if BYTES_PER_MPI_LIMB == 2 #define X "4" #elif BYTES_PER_MPI_LIMB == 4 #define X "8" #elif BYTES_PER_MPI_LIMB == 8 #define X "16" #else #error please define the format here #endif buffer[n] = '0'; buffer[n+1] = 'x'; n += 2; for(i=a->nlimbs; i > 0 ; i-- ) { n += sprintf(buffer+n, i!=a->nlimbs? "%0" X "lX":"%lX", (ulong)a->d[i-1]); #undef X } if( !a->nlimbs ) { buffer[n] = '0'; n++; } } return n; }
/********************************************* ************** interface ****************** *********************************************/ static gcry_mpi_t ec2os (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t p) { gpg_error_t err; int pbytes = (mpi_get_nbits (p)+7)/8; size_t n; unsigned char *buf, *ptr; gcry_mpi_t result; buf = gcry_xmalloc ( 1 + 2*pbytes ); *buf = 04; /* Uncompressed point. */ ptr = buf+1; err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, x); if (err) log_fatal ("mpi_print failed: %s\n", gpg_strerror (err)); if (n < pbytes) { memmove (ptr+(pbytes-n), ptr, n); memset (ptr, 0, (pbytes-n)); } ptr += pbytes; err = gcry_mpi_print (GCRYMPI_FMT_USG, ptr, pbytes, &n, y); if (err) log_fatal ("mpi_print failed: %s\n", gpg_strerror (err)); if (n < pbytes) { memmove (ptr+(pbytes-n), ptr, n); memset (ptr, 0, (pbytes-n)); } err = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, buf, 1+2*pbytes, NULL); if (err) log_fatal ("mpi_scan failed: %s\n", gpg_strerror (err)); gcry_free (buf); mpi_free (x); mpi_free (y); return result; }
KBNODE make_mpi_comment_node( const char *s, MPI a ) { PACKET *pkt; byte *buf, *p, *pp; unsigned n1, nb1; size_t n = strlen(s); nb1 = mpi_get_nbits( a ); p = buf = mpi_get_buffer( a, &n1, NULL ); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n + 2 + n1 ); pkt->pkt.comment->len = n+1+2+n1; pp = pkt->pkt.comment->data; memcpy(pp, s, n+1); pp[n+1] = nb1 >> 8; pp[n+2] = nb1 ; memcpy(pp+n+3, p, n1 ); m_free(buf); return new_kbnode( pkt ); }
int rsa_verify_sig(char *sig, int sig_size, u8 *sha1) { MPI public_key[2]; MPI hash; MPI data; int nread; int nframe; if (!rsa_key) { return -EINVAL; } /* initialize our keys */ nread = rsa_key->n_size; public_key[0] = mpi_read_from_buffer((byte *)rsa_key->n, &nread, 0); if (!public_key[0]) { return -EINVAL; } nread = rsa_key->e_size; public_key[1] = mpi_read_from_buffer((byte *)rsa_key->e, &nread, 0); if (!public_key[1]) { return -EINVAL; } /* set up the MPI for the sig */ data = mpi_read_from_buffer(sig, &sig_size, 0); if (!data) { return -EINVAL; } /* set up the MPI for the result */ nframe = mpi_get_nbits(public_key[0]); hash = do_encode_md(sha1, nframe); /* verify the sig */ return rsa_verify(hash, &data, public_key); }
int digsig_rsa_bsign_verify(unsigned char *hash_format, int length, unsigned char *signed_hash) { int rc = 0, cmp; MPI hash, data; unsigned nread = DIGSIG_ELF_SIG_SIZE; int nframe; unsigned char sig_class; unsigned char sig_timestamp[SIZEOF_UNSIGNED_INT]; int i; SIGCTX *ctx = NULL; unsigned char *new_sig; new_sig = kmalloc(gDigestLength[HASH_SHA1], DIGSIG_SAFE_ALLOC); if (!new_sig) { DSM_ERROR ("kmalloc failed in %s for new_sig\n", __FUNCTION__); return -ENOMEM; } /* Get MPI of signed data from .sig file/section */ nread = DIGSIG_ELF_SIG_SIZE; data = mpi_read_from_buffer(signed_hash + DIGSIG_RSA_DATA_OFFSET, &nread, 0); if (!data) { kfree(new_sig); return -EINVAL; } /* Get MPI for hash */ /* bsign modif - file hash - gpg modif */ /* bsign modif: add bsign greet at beginning */ /* gpg modif: add class and timestamp at end */ ctx = kmalloc(sizeof(SIGCTX), GFP_KERNEL); if (!ctx) { DSM_ERROR("Cannot allocate ctx\n"); mpi_free (data); kfree (new_sig); return -ENOMEM; } ctx->tvmem = kmalloc(TVMEMSIZE, GFP_KERNEL); if (!ctx->tvmem) { kfree (ctx); mpi_free(data); kfree (new_sig); DSM_ERROR("Cannot allocate plaintext buffer\n"); return -ENOMEM; } digsig_sha1_init(ctx); sig_class = signed_hash[DIGSIG_RSA_CLASS_OFFSET]; sig_class &= 0xff; for (i = 0; i < SIZEOF_UNSIGNED_INT; i++) { sig_timestamp[i] = signed_hash[DIGSIG_RSA_TIMESTAMP_OFFSET + i] & 0xff; } digsig_sha1_update(ctx, DIGSIG_BSIGN_STRING, DIGSIG_BSIGN_GREET_SIZE); digsig_sha1_update(ctx, hash_format, SHA1_DIGEST_LENGTH); digsig_sha1_update(ctx, &sig_class, 1); digsig_sha1_update(ctx, sig_timestamp, SIZEOF_UNSIGNED_INT); if ((rc = digsig_sha1_final(ctx, new_sig)) < 0) { DSM_ERROR ("internal_rsa_verify_final Cannot finalize hash algorithm\n"); mpi_free(data); kfree(ctx->tvmem); kfree(ctx); return rc; } nframe = mpi_get_nbits(digsig_public_key[0]); hash = do_encode_md(new_sig, nframe); if (hash == MPI_NULL) { DSM_PRINT(DEBUG_SIGN, "mpi creation failed\\n"); } /* Do RSA verification */ cmp = rsa_verify(hash, &data, digsig_public_key); rc = cmp ? -EPERM : 0; mpi_free(hash); mpi_free(data); kfree(ctx->tvmem); kfree(ctx); kfree (new_sig); return rc; }
/* * Generate a random secret exponent K less than Q. * Note that ECDSA uses this code also to generate D. */ gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level) { gcry_mpi_t k = mpi_alloc_secure (mpi_get_nlimbs (q)); unsigned int nbits = mpi_get_nbits (q); unsigned int nbytes = (nbits+7)/8; char *rndbuf = NULL; /* To learn why we don't use mpi_mod to get the requested bit size, read the paper: "The Insecurity of the Digital Signature Algorithm with Partially Known Nonces" by Nguyen and Shparlinski. Journal of Cryptology, New York. Vol 15, nr 3 (2003) */ if (DBG_CIPHER) log_debug ("choosing a random k of %u bits at seclevel %d\n", nbits, security_level); for (;;) { if ( !rndbuf || nbits < 32 ) { xfree (rndbuf); rndbuf = _gcry_random_bytes_secure (nbytes, security_level); } else { /* Change only some of the higher bits. We could improve this by directly requesting more memory at the first call to get_random_bytes() and use these extra bytes here. However the required management code is more complex and thus we better use this simple method. */ char *pp = _gcry_random_bytes_secure (4, security_level); memcpy (rndbuf, pp, 4); xfree (pp); } _gcry_mpi_set_buffer (k, rndbuf, nbytes, 0); /* Make sure we have the requested number of bits. This code looks a bit funny but it is easy to understand if you consider that mpi_set_highbit clears all higher bits. We don't have a clear_highbit, thus we first set the high bit and then clear it again. */ if (mpi_test_bit (k, nbits-1)) mpi_set_highbit (k, nbits-1); else { mpi_set_highbit (k, nbits-1); mpi_clear_bit (k, nbits-1); } if (!(mpi_cmp (k, q) < 0)) /* check: k < q */ { if (DBG_CIPHER) log_debug ("\tk too large - again\n"); continue; /* no */ } if (!(mpi_cmp_ui (k, 0) > 0)) /* check: k > 0 */ { if (DBG_CIPHER) log_debug ("\tk is zero - again\n"); continue; /* no */ } break; /* okay */ } xfree (rndbuf); return k; }
/* Generate a key pair with a key of size NBITS not using a random value for the secret key but the one given as X. This is useful to implement a passphrase based decryption for a public key based encryption. It has appliactions in backup systems. Returns: A structure filled with all needed values and an array with n-1 factors of (p-1). */ static gcry_err_code_t generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x, gcry_mpi_t **ret_factors ) { gcry_mpi_t p; /* The prime. */ gcry_mpi_t p_min1; /* The prime minus 1. */ gcry_mpi_t g; /* The generator. */ gcry_mpi_t y; /* g^x mod p. */ unsigned int qbits; unsigned int xbits; sk->p = NULL; sk->g = NULL; sk->y = NULL; sk->x = NULL; /* Do a quick check to see whether X is suitable. */ xbits = mpi_get_nbits (x); if ( xbits < 64 || xbits >= nbits ) return GPG_ERR_INV_VALUE; p_min1 = gcry_mpi_new ( nbits ); qbits = wiener_map ( nbits ); if ( (qbits & 1) ) /* Better have an even one. */ qbits++; g = mpi_alloc (1); p = _gcry_generate_elg_prime ( 0, nbits, qbits, g, ret_factors ); mpi_sub_ui (p_min1, p, 1); if (DBG_CIPHER) log_debug ("using a supplied x of size %u", xbits ); if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) ) { gcry_mpi_release ( p_min1 ); gcry_mpi_release ( p ); gcry_mpi_release ( g ); return GPG_ERR_INV_VALUE; } y = gcry_mpi_new (nbits); gcry_mpi_powm ( y, g, x, p ); if ( DBG_CIPHER ) { progress ('\n'); log_mpidump ("elg p= ", p ); log_mpidump ("elg g= ", g ); log_mpidump ("elg y= ", y ); log_mpidump ("elg x= ", x ); } /* Copy the stuff to the key structures */ sk->p = p; sk->g = g; sk->y = y; sk->x = gcry_mpi_copy (x); gcry_mpi_release ( p_min1 ); /* Now we can test our keys. */ if ( test_keys ( sk, nbits - 64, 1 ) ) { gcry_mpi_release ( sk->p ); sk->p = NULL; gcry_mpi_release ( sk->g ); sk->g = NULL; gcry_mpi_release ( sk->y ); sk->y = NULL; gcry_mpi_release ( sk->x ); sk->x = NULL; return GPG_ERR_BAD_SECKEY; } return 0; }
/**************** * Generate a random secret exponent k from prime p, so that k is * relatively prime to p-1. With SMALL_K set, k will be selected for * better encryption performance - this must never be used signing! */ static gcry_mpi_t gen_k( gcry_mpi_t p, int small_k ) { gcry_mpi_t k = mpi_alloc_secure( 0 ); gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(p) ); gcry_mpi_t p_1 = mpi_copy(p); unsigned int orig_nbits = mpi_get_nbits(p); unsigned int nbits, nbytes; char *rndbuf = NULL; if (small_k) { /* Using a k much lesser than p is sufficient for encryption and * it greatly improves the encryption performance. We use * Wiener's table and add a large safety margin. */ nbits = wiener_map( orig_nbits ) * 3 / 2; if( nbits >= orig_nbits ) BUG(); } else nbits = orig_nbits; nbytes = (nbits+7)/8; if( DBG_CIPHER ) log_debug("choosing a random k "); mpi_sub_ui( p_1, p, 1); for(;;) { if( !rndbuf || nbits < 32 ) { gcry_free(rndbuf); rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM ); } else { /* Change only some of the higher bits. We could improve this by directly requesting more memory at the first call to get_random_bytes() and use this the here maybe it is easier to do this directly in random.c Anyway, it is highly inlikely that we will ever reach this code. */ char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM ); memcpy( rndbuf, pp, 4 ); gcry_free(pp); } _gcry_mpi_set_buffer( k, rndbuf, nbytes, 0 ); for(;;) { if( !(mpi_cmp( k, p_1 ) < 0) ) /* check: k < (p-1) */ { if( DBG_CIPHER ) progress('+'); break; /* no */ } if( !(mpi_cmp_ui( k, 0 ) > 0) ) /* check: k > 0 */ { if( DBG_CIPHER ) progress('-'); break; /* no */ } if (gcry_mpi_gcd( temp, k, p_1 )) goto found; /* okay, k is relative prime to (p-1) */ mpi_add_ui( k, k, 1 ); if( DBG_CIPHER ) progress('.'); } } found: gcry_free(rndbuf); if( DBG_CIPHER ) progress('\n'); mpi_free(p_1); mpi_free(temp); return k; }
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; } } } }
/**************** * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M */ int mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m) { int rc = -ENOMEM; int k; /* number of elements */ int t; /* bit size of largest exponent */ int i, j, idx; MPI *G = NULL; /* table with precomputed values of size 2^k */ MPI tmp = NULL; for(k=0; basearray[k]; k++ ) ; if (!k) { printk("mpi_mulpowm: assert(k) failed\n"); BUG(); } for(t=0, i=0; (tmp=exparray[i]); i++ ) { j = mpi_get_nbits(tmp); if( j > t ) t = j; } if (i!=k) { printk("mpi_mulpowm: assert(i==k) failed\n"); BUG(); } if (!t) { printk("mpi_mulpowm: assert(t) failed\n"); BUG(); } if (k>=10) { printk("mpi_mulpowm: assert(k<10) failed\n"); BUG(); } //daveti: hack //G = kzalloc( (1<<k) * sizeof *G, GFP_KERNEL ); G = kzalloc( (1<<k) * sizeof *G, GFP_ATOMIC ); if (!G) goto nomem; /* and calculate */ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 ); if (!tmp) goto nomem; if (mpi_set_ui( res, 1 ) < 0) goto nomem; for(i = 1; i <= t; i++ ) { if (mpi_mulm(tmp, res, res, m ) < 0) goto nomem; idx = build_index( exparray, k, i, t ); if (!(idx >= 0 && idx < (1<<k))) { printk("mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed\n"); BUG(); } if( !G[idx] ) { if( !idx ) { G[0] = mpi_alloc_set_ui( 1 ); if (!G[0]) goto nomem; } else { for(j=0; j < k; j++ ) { if( (idx & (1<<j) ) ) { if( !G[idx] ) { if (mpi_copy( &G[idx], basearray[j] ) < 0) goto nomem; } else { if (mpi_mulm(G[idx],G[idx],basearray[j],m) < 0) goto nomem; } } } if( !G[idx] ) { G[idx] = mpi_alloc(0); if (!G[idx]) goto nomem; } } } if (mpi_mulm(res, tmp, G[idx], m ) < 0) goto nomem; } rc = 0; nomem: /* cleanup */ mpi_free(tmp); for(i=0; i < (1<<k); i++ ) mpi_free(G[i]); kfree(G); return rc; }
/* Scalar point multiplication - the main function for ECC. If takes an integer SCALAR and a POINT as well as the usual context CTX. RESULT will be set to the resulting point. */ void _gcry_mpi_ec_mul_point (mpi_point_t result, gcry_mpi_t scalar, mpi_point_t point, mpi_ec_t ctx) { #if 0 /* Simple left to right binary method. GECC Algorithm 3.27 */ unsigned int nbits; int i; nbits = mpi_get_nbits (scalar); mpi_set_ui (result->x, 1); mpi_set_ui (result->y, 1); mpi_set_ui (result->z, 0); for (i=nbits-1; i >= 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (scalar, i) == 1) _gcry_mpi_ec_add_points (result, result, point, ctx); } #else gcry_mpi_t x1, y1, z1, k, h, yy; unsigned int i, loops; mpi_point_struct p1, p2, p1inv; x1 = mpi_alloc_like (ctx->p); y1 = mpi_alloc_like (ctx->p); h = mpi_alloc_like (ctx->p); k = mpi_copy (scalar); yy = mpi_copy (point->y); if ( mpi_is_neg (k) ) { k->sign = 0; ec_invm (yy, yy, ctx); } if (!mpi_cmp_ui (point->z, 1)) { mpi_set (x1, point->x); mpi_set (y1, yy); } else { gcry_mpi_t z2, z3; z2 = mpi_alloc_like (ctx->p); z3 = mpi_alloc_like (ctx->p); ec_mulm (z2, point->z, point->z, ctx); ec_mulm (z3, point->z, z2, ctx); ec_invm (z2, z2, ctx); ec_mulm (x1, point->x, z2, ctx); ec_invm (z3, z3, ctx); ec_mulm (y1, yy, z3, ctx); mpi_free (z2); mpi_free (z3); } z1 = mpi_copy (mpi_const (MPI_C_ONE)); mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */ loops = mpi_get_nbits (h); if (loops < 2) { /* If SCALAR is zero, the above mpi_mul sets H to zero and thus LOOPs will be zero. To avoid an underflow of I in the main loop we set LOOP to 2 and the result to (0,0,0). */ loops = 2; mpi_clear (result->x); mpi_clear (result->y); mpi_clear (result->z); } else { mpi_set (result->x, point->x); mpi_set (result->y, yy); mpi_set (result->z, point->z); } mpi_free (yy); yy = NULL; p1.x = x1; x1 = NULL; p1.y = y1; y1 = NULL; p1.z = z1; z1 = NULL; point_init (&p2); point_init (&p1inv); for (i=loops-2; i > 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0) { point_set (&p2, result); _gcry_mpi_ec_add_points (result, &p2, &p1, ctx); } if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1) { point_set (&p2, result); /* Invert point: y = p - y mod p */ point_set (&p1inv, &p1); ec_subm (p1inv.y, ctx->p, p1inv.y, ctx); _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx); } } point_free (&p1); point_free (&p2); point_free (&p1inv); mpi_free (h); mpi_free (k); #endif }
/* * Generate a deterministic secret exponent K less than DSA_Q. H1 is * the to be signed digest with a length of HLEN bytes. HALGO is the * algorithm used to create the hash. On success the value for K is * stored at R_K. */ gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k, gcry_mpi_t dsa_q, gcry_mpi_t dsa_x, const unsigned char *h1, unsigned int hlen, int halgo, unsigned int extraloops) { gpg_err_code_t rc; unsigned char *V = NULL; unsigned char *K = NULL; unsigned char *x_buf = NULL; unsigned char *h1_buf = NULL; gcry_md_hd_t hd = NULL; unsigned char *t = NULL; gcry_mpi_t k = NULL; unsigned int tbits, qbits; int i; qbits = mpi_get_nbits (dsa_q); if (!qbits || !h1 || !hlen) return GPG_ERR_EINVAL; if (_gcry_md_get_algo_dlen (halgo) != hlen) return GPG_ERR_DIGEST_ALGO; /* Step b: V = 0x01 0x01 0x01 ... 0x01 */ V = xtrymalloc (hlen); if (!V) { rc = gpg_err_code_from_syserror (); goto leave; } for (i=0; i < hlen; i++) V[i] = 1; /* Step c: K = 0x00 0x00 0x00 ... 0x00 */ K = xtrycalloc (1, hlen); if (!K) { rc = gpg_err_code_from_syserror (); goto leave; } rc = int2octets (&x_buf, dsa_x, (qbits+7)/8); if (rc) goto leave; rc = bits2octets (&h1_buf, h1, hlen*8, dsa_q, qbits); if (rc) goto leave; /* Create a handle to compute the HMACs. */ rc = _gcry_md_open (&hd, halgo, (GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)); if (rc) goto leave; /* Step d: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step e: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step f: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "\x01", 1); _gcry_md_write (hd, x_buf, (qbits+7)/8); _gcry_md_write (hd, h1_buf, (qbits+7)/8); memcpy (K, _gcry_md_read (hd, 0), hlen); /* Step g: V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* Step h. */ t = xtrymalloc ((qbits+7)/8+hlen); if (!t) { rc = gpg_err_code_from_syserror (); goto leave; } again: for (tbits = 0; tbits < qbits;) { /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); /* T = T || V */ memcpy (t+(tbits+7)/8, V, hlen); tbits += 8*hlen; } /* k = bits2int (T) */ mpi_free (k); k = NULL; rc = _gcry_mpi_scan (&k, GCRYMPI_FMT_USG, t, (tbits+7)/8, NULL); if (rc) goto leave; if (tbits > qbits) mpi_rshift (k, k, tbits - qbits); /* Check: k < q and k > 1 */ if (!(mpi_cmp (k, dsa_q) < 0 && mpi_cmp_ui (k, 0) > 0)) { /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* The caller may have requested that we introduce some extra loops. This is for example useful if the caller wants another value for K because the last returned one yielded an R of 0. Because this is very unlikely we implement it in a straightforward way. */ if (extraloops) { extraloops--; /* K = HMAC_K(V || 0x00) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); _gcry_md_write (hd, "", 1); memcpy (K, _gcry_md_read (hd, 0), hlen); /* V = HMAC_K(V) */ rc = _gcry_md_setkey (hd, K, hlen); if (rc) goto leave; _gcry_md_write (hd, V, hlen); memcpy (V, _gcry_md_read (hd, 0), hlen); goto again; } /* log_mpidump (" k", k); */ leave: xfree (t); _gcry_md_close (hd); xfree (h1_buf); xfree (x_buf); xfree (K); xfree (V); if (rc) mpi_free (k); else *r_k = k; return rc; }
/* * Return true if n is probably a prime */ static int is_prime (gcry_mpi_t n, int steps, unsigned int *count) { gcry_mpi_t x = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t z = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t nminus1 = mpi_alloc( mpi_get_nlimbs( n ) ); gcry_mpi_t a2 = mpi_alloc_set_ui( 2 ); gcry_mpi_t q; unsigned i, j, k; int rc = 0; unsigned nbits = mpi_get_nbits( n ); mpi_sub_ui( nminus1, n, 1 ); /* Find q and k, so that n = 1 + 2^k * q . */ q = mpi_copy ( nminus1 ); k = mpi_trailing_zeros ( q ); mpi_tdiv_q_2exp (q, q, k); for (i=0 ; i < steps; i++ ) { ++*count; if( !i ) { mpi_set_ui( x, 2 ); } else { gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM ); /* Make sure that the number is smaller than the prime and keep the randomness of the high bit. */ if ( mpi_test_bit ( x, nbits-2) ) { mpi_set_highbit ( x, nbits-2); /* Clear all higher bits. */ } else { mpi_set_highbit( x, nbits-2 ); mpi_clear_bit( x, nbits-2 ); } assert ( mpi_cmp( x, nminus1 ) < 0 && mpi_cmp_ui( x, 1 ) > 0 ); } gcry_mpi_powm ( y, x, q, n); if ( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) { for ( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) { gcry_mpi_powm(y, y, a2, n); if( !mpi_cmp_ui( y, 1 ) ) goto leave; /* Not a prime. */ } if (mpi_cmp( y, nminus1 ) ) goto leave; /* Not a prime. */ } progress('+'); } rc = 1; /* May be a prime. */ leave: mpi_free( x ); mpi_free( y ); mpi_free( z ); mpi_free( nminus1 ); mpi_free( q ); mpi_free( a2 ); return rc; }
/**************** * 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; }