static void initialize(void) { /* The data buffer is allocated somewhat larger, so that * we can use this extra space (which is allocated in secure memory) * as a temporary hash buffer */ rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN) : m_alloc_clear(POOLSIZE+BLOCKLEN); keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN) : m_alloc_clear(POOLSIZE+BLOCKLEN); is_initialized = 1; }
/**************** * Get the session key from a pubkey enc paket and return * it in DEK, which should have been allocated in secure memory. */ int get_session_key( PKT_pubkey_enc *k, DEK *dek ) { PKT_secret_key *sk = NULL; int rc; rc = check_pubkey_algo( k->pubkey_algo ); if( rc ) goto leave; if( (k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets ) { sk = m_alloc_clear( sizeof *sk ); sk->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/ if( !(rc = get_seckey( sk, k->keyid )) ) rc = get_it( k, dek, sk, k->keyid ); } else { /* anonymous receiver: Try all available secret keys */ void *enum_context = NULL; u32 keyid[2]; for(;;) { if( sk ) free_secret_key( sk ); sk = m_alloc_clear( sizeof *sk ); rc=enum_secret_keys( &enum_context, sk, 1); if( rc ) { rc = G10ERR_NO_SECKEY; break; } if( sk->pubkey_algo != k->pubkey_algo ) continue; keyid_from_sk( sk, keyid ); log_info(_("anonymous receiver; trying secret key %08lX ...\n"), (ulong)keyid[1] ); rc = check_secret_key( sk, 1 ); /* ask only once */ if( !rc ) rc = get_it( k, dek, sk, keyid ); if( !rc ) { log_info(_("okay, we are the anonymous recipient.\n") ); break; } } enum_secret_keys( &enum_context, NULL, 0 ); /* free context */ } leave: if( sk ) free_secret_key( sk ); return rc; }
void mpihelp_mul_karatsuba_case( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, mpi_ptr_t vp, mpi_size_t vsize, struct karatsuba_ctx *ctx ) { mpi_limb_t cy; if( !ctx->tspace || ctx->tspace_size < vsize ) { if( ctx->tspace ) mpi_free_limb_space( ctx->tspace ); ctx->tspace = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up ) || m_is_secure( vp ) ); ctx->tspace_size = vsize; } MPN_MUL_N_RECURSE( prodp, up, vp, vsize, ctx->tspace ); prodp += vsize; up += vsize; usize -= vsize; if( usize >= vsize ) { if( !ctx->tp || ctx->tp_size < vsize ) { if( ctx->tp ) mpi_free_limb_space( ctx->tp ); ctx->tp = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up ) || m_is_secure( vp ) ); ctx->tp_size = vsize; } do { MPN_MUL_N_RECURSE( ctx->tp, up, vp, vsize, ctx->tspace ); cy = mpihelp_add_n( prodp, prodp, ctx->tp, vsize ); mpihelp_add_1( prodp + vsize, ctx->tp + vsize, vsize, cy ); prodp += vsize; up += vsize; usize -= vsize; } while( usize >= vsize ); } if( usize ) { if( usize < KARATSUBA_THRESHOLD ) { mpihelp_mul( ctx->tspace, vp, vsize, up, usize ); } else { if( !ctx->next ) { ctx->next = m_alloc_clear( sizeof *ctx ); } mpihelp_mul_karatsuba_case( ctx->tspace, vp, vsize, up, usize, ctx->next ); } cy = mpihelp_add_n( prodp, prodp, ctx->tspace, vsize); mpihelp_add_1( prodp + vsize, ctx->tspace + vsize, usize, cy ); } }
KBNODE make_comment_node( const char *s ) { PACKET *pkt; size_t n = strlen(s); pkt = m_alloc_clear( sizeof *pkt ); pkt->pkttype = PKT_COMMENT; pkt->pkt.comment = m_alloc( sizeof *pkt->pkt.comment + n - 1 ); pkt->pkt.comment->len = n; strcpy(pkt->pkt.comment->data, s); return new_kbnode( pkt ); }
char * parser_create_req (char *buff) { char address[16] = { 0 }; char *ret = NULL; struct in_addr tmpaddr; strncpy (address, buff, 15); if (inet_aton (address, &tmpaddr)) { ret = m_alloc_clear (5 + strlen (address) + 2); strcat (ret, "Req: "); strcat (ret, address); strcat (ret, "\n"); } return ret; }
/**************** * Handle a compressed packet */ int handle_compressed( void *procctx, PKT_compressed *cd, int (*callback)(IOBUF, void *), void *passthru ) { compress_filter_context_t *cfx; int rc; if( cd->algorithm < 1 || cd->algorithm > 2 ) return G10ERR_COMPR_ALGO; cfx = m_alloc_clear (sizeof *cfx); cfx->algo = cd->algorithm; cfx->release = release_context; iobuf_push_filter( cd->buf, compress_filter, cfx ); if( callback ) rc = callback(cd->buf, passthru ); else rc = proc_packets(procctx, cd->buf); cd->buf = NULL; return rc; }
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 parse_body (char *buffer, int length, struct body_msg *body) { char *tmp = buffer; char *end = buffer + length; int offset; int off; char *bodyline; char *address; uint16_t port = 0; size_t keylen; struct reg_body *tmp_body = NULL; struct id_body *tmp_body1 = NULL; struct add_body *tmp_body2 = NULL; struct key_body *tmp_body3 = NULL; /* strip the beginning space */ for (tmp; ((*tmp == '\n') || (*tmp == '\r')) && ((tmp - buffer) < length); tmp++); offset = tmp - buffer; do { switch (*tmp) { case 'U': case 'u': { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (off = check ("USER", 4, tmp, end)) { if (LOG_PARSER) log_info ("Body USER found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the user address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); /* copy it to structure */ tmp_body->user = (char *) strndup (tmp, buffer + offset - tmp - 1); tmp_body->user_len = buffer + offset - tmp - 1; if (LOG_PARSER) log_info ("The user is : %s\n", tmp_body->user); tmp = buffer + offset; break; } } case 'A': case 'a': { if (off = check ("ADDRESS", 7, tmp, end)) { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (LOG_PARSER) log_info ("Body ADDRESS found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the IP address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); /* copy it to structure */ tmp_body->ip = (char *) strndup (tmp, buffer + offset - tmp - 1); tmp_body->ip_len = buffer + offset - tmp - 1; if (LOG_PARSER) log_info ("The IP address is : %s\n", tmp_body->ip); tmp = buffer + offset; break; } else if (off = check ("ADDER", 5, tmp, end)) { char *data; MPI val = mpi_alloc (0); if (!tmp_body2) tmp_body2 = create_add_body (); body->type = BODYADD; if (LOG_PARSER) log_info ("Body Adder found in %u\n", tmp - buffer); offset += off; /* find the end of this line */ offset += find_end (tmp + off, end); /* find the adder */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); data = m_alloc_clear (buffer + offset - tmp); strncpy (data, tmp, buffer + offset - tmp - 1); if (mpi_fromstr (val, data)) { mpi_free (val); m_free (data); tmp = buffer + offset; break; } tmp_body2->adder[tmp_body2->num] = val; (tmp_body2->num)++; m_free (data); tmp = buffer + offset; break; } } case 'P': case 'p': { if (off = check ("PORT", 4, tmp, end)) { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (LOG_PARSER) log_info ("Body PORT found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the user address */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); for (tmp; tmp < (buffer + offset - 1); tmp++) { if ((*tmp - 48) <= 9 && (*tmp - 48) >= 0) port = port * 10 + (*tmp - 48); else { log_error ("Error while changing port to number\n"); return 1; } } /* copy it to structure */ tmp_body->port = port; if (LOG_PARSER) log_info ("The PORT is : %u\n", port); tmp = buffer + offset; break; } } case '-': { if (!tmp_body) tmp_body = create_reg_body (); body->type = BODYREG; if (keylen = check_public_key (tmp, end)) { tmp_body->public_key = (char *) strndup (tmp, keylen); tmp_body->pk_len = keylen; if (LOG_PARSER) log_info ("We found begin pgp length : %u\n" "%s\n", keylen, strndup (tmp, keylen)); tmp += (keylen + 1); } } break; case 'I': case 'i': { uint32_t address; char c; if (!tmp_body1) tmp_body1 = create_id_body (); body->type = BODYID; if (off = check ("ID_LIST", 7, tmp, end)) { if (LOG_PARSER) log_info ("Body id list found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the id */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); if (sscanf (tmp, "%x%c", &address, &c) == 2) { tmp_body1->id[tmp_body1->num] = address; (tmp_body1->num)++; } tmp = buffer + offset; break; } } case 'K': case 'k': { int length; if (!tmp_body3) tmp_body3 = create_key_body (); body->type = BODYKEY; if (off = check ("KEY", 3, tmp, end)) { if (LOG_PARSER) log_info ("Body key found in %u\n", tmp - buffer); offset += off; /* find the end of this header */ offset += find_end (tmp + off, end); /* find the key */ tmp = tmp + off; for (tmp; (*tmp == ' ') && ((tmp) < end); tmp++); length = buffer + offset - tmp; tmp_body3->radmsg = m_alloc (length); strncpy (tmp_body3->radmsg, tmp, length - 1); tmp_body3->radmsg[length] = '\0'; tmp_body3->length = length - 1; tmp = buffer + offset; break; } } default: { log_error ("Other body type is found %c. Dont know what to do in %u\n", *tmp, tmp - buffer); return 1; } } } while (*tmp != '\n' && *tmp != '\r' && tmp < end); if (body->type == BODYREG) { /* check if any field is empty, we need a full one */ if (!tmp_body->user || !tmp_body->ip || (tmp_body->port == 0) || !tmp_body->public_key) { if (tmp_body->user) m_free (tmp_body->user); if (tmp_body->ip) m_free (tmp_body->ip); if (tmp_body->public_key) m_free (tmp_body->public_key); m_free (tmp_body); return 1; } else { body->msg.regbody = tmp_body; tmp_body = NULL; return 0; } } else if (body->type == BODYID) { body->msg.idbody = tmp_body1; tmp_body1 = NULL; return 0; } else if (body->type == BODYADD) { body->msg.addbody = tmp_body2; tmp_body2 = NULL; return 0; } else if (body->type == BODYKEY) { body->msg.keybody = tmp_body3; tmp_body2 = NULL; return 0; } return 1; }
int signature_check2( PKT_signature *sig, MD_HANDLE digest, u32 *r_expiredate, int *r_expired ) { PKT_public_key *pk = m_alloc_clear( sizeof *pk ); int rc=0; *r_expiredate = 0; /* Sanity check that the md has a context for the hash that the sig is expecting. This can happen if a onepass sig header does not match the actual sig, and also if the clearsign "Hash:" header is missing or does not match the actual sig. */ if(!md_algo_present(digest,sig->digest_algo)) { log_info(_("WARNING: signature digest conflict in message\n")); rc=G10ERR_BAD_SIGN; } else if( get_pubkey( pk, sig->keyid ) ) rc = G10ERR_NO_PUBKEY; else if(!pk->is_valid && !pk->is_primary) rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an invalid subkey */ else { *r_expiredate = pk->expiredate; rc = do_check( pk, sig, digest, r_expired ); } free_public_key( pk ); if( !rc && sig->sig_class < 2 && is_status_enabled() ) { /* This signature id works best with DLP algorithms because * they use a random parameter for every signature. Instead of * this sig-id we could have also used the hash of the document * and the timestamp, but the drawback of this is, that it is * not possible to sign more than one identical document within * one second. Some remote batch processing applications might * like this feature here */ MD_HANDLE md; u32 a = sig->timestamp; int i, nsig = pubkey_get_nsig( sig->pubkey_algo ); byte *p, *buffer; md = md_open( DIGEST_ALGO_RMD160, 0); md_putc( digest, sig->pubkey_algo ); md_putc( digest, sig->digest_algo ); md_putc( digest, (a >> 24) & 0xff ); md_putc( digest, (a >> 16) & 0xff ); md_putc( digest, (a >> 8) & 0xff ); md_putc( digest, a & 0xff ); for(i=0; i < nsig; i++ ) { unsigned n = mpi_get_nbits( sig->data[i]); md_putc( md, n>>8); md_putc( md, n ); p = mpi_get_buffer( sig->data[i], &n, NULL ); md_write( md, p, n ); m_free(p); } md_final( md ); p = make_radix64_string( md_read( md, 0 ), 20 ); buffer = m_alloc( strlen(p) + 60 ); sprintf( buffer, "%s %s %lu", p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp ); write_status_text( STATUS_SIG_ID, buffer ); m_free(buffer); m_free(p); md_close(md); }
void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m) { int k; /* number of elements */ int t; /* bit size of largest exponent */ int i, j, idx; MPI *G; /* table with precomputed values of size 2^k */ MPI tmp; #ifdef USE_BARRETT MPI barrett_y, barrett_r1, barrett_r2; int barrett_k; #endif for(k=0; basearray[k]; k++ ) ; passert(k); for(t=0, i=0; (tmp=exparray[i]); i++ ) { /*log_mpidump("exp: ", tmp );*/ j = mpi_get_nbits(tmp); if( j > t ) t = j; } /*log_mpidump("mod: ", m );*/ passert(i==k); passert(t); passert( k < 10 ); #ifdef PLUTO m_alloc_ptrs_clear(G, 1<<k); #else G = m_alloc_clear( (1<<k) * sizeof *G ); #endif #ifdef USE_BARRETT barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 ); #endif /* and calculate */ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 ); mpi_set_ui( res, 1 ); for(i = 1; i <= t; i++ ) { barrett_mulm(tmp, res, res, m, barrett_y, barrett_k, barrett_r1, barrett_r2 ); idx = build_index( exparray, k, i, t ); passert( idx >= 0 && idx < (1<<k) ); if( !G[idx] ) { if( !idx ) G[0] = mpi_alloc_set_ui( 1 ); else { for(j=0; j < k; j++ ) { if( (idx & (1<<j) ) ) { if( !G[idx] ) G[idx] = mpi_copy( basearray[j] ); else barrett_mulm( G[idx], G[idx], basearray[j], m, barrett_y, barrett_k, barrett_r1, barrett_r2 ); } } if( !G[idx] ) G[idx] = mpi_alloc(0); } } barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 ); } /* cleanup */ mpi_free(tmp); #ifdef USE_BARRETT mpi_free(barrett_y); mpi_free(barrett_r1); mpi_free(barrett_r2); #endif for(i=0; i < (1<<k); i++ ) mpi_free(G[i]); m_free(G); }
int compress_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { size_t size = *ret_len; compress_filter_context_t *zfx = opaque; z_stream *zs = zfx->opaque; int rc=0; if( control == IOBUFCTRL_UNDERFLOW ) { if( !zfx->status ) { zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_uncompress( zfx, zs ); zfx->status = 1; } #ifndef __riscos__ zs->next_out = buf; #else /* __riscos__ */ zs->next_out = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_out = size; zfx->outbufsize = size; /* needed only for calculation */ rc = do_uncompress( zfx, zs, a, ret_len ); } else if( control == IOBUFCTRL_FLUSH ) { if( !zfx->status ) { PACKET pkt; PKT_compressed cd; if( !zfx->algo ) zfx->algo = DEFAULT_COMPRESS_ALGO; if( zfx->algo != 1 && zfx->algo != 2 ) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; cd.algorithm = zfx->algo; init_packet( &pkt ); pkt.pkttype = PKT_COMPRESSED; pkt.pkt.compressed = &cd; if( build_packet( a, &pkt )) log_bug("build_packet(PKT_COMPRESSED) failed\n"); zs = zfx->opaque = m_alloc_clear( sizeof *zs ); init_compress( zfx, zs ); zfx->status = 2; } #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = size; rc = do_compress( zfx, zs, Z_NO_FLUSH, a ); } else if( control == IOBUFCTRL_FREE ) { if( zfx->status == 1 ) { inflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } else if( zfx->status == 2 ) { #ifndef __riscos__ zs->next_in = buf; #else /* __riscos__ */ zs->next_in = (Bytef *) buf; #endif /* __riscos__ */ zs->avail_in = 0; do_compress( zfx, zs, Z_FINISH, a ); deflateEnd(zs); m_free(zs); zfx->opaque = NULL; m_free(zfx->outbuf); zfx->outbuf = NULL; } if (zfx->release) zfx->release (zfx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "compress_filter"; return rc; }
/**************** * Create a lockfile with the given name and return an object of * type DOTLOCK which may be used later to actually do the lock. * A cleanup routine gets installed to cleanup left over locks * or other files used together with the lockmechanism. * Althoug the function is called dotlock, this does not necessarily * mean that real lockfiles are used - the function may decide to * use fcntl locking. Calling the function with NULL only install * the atexit handler and maybe used to assure that the cleanup * is called after all other atexit handlers. * * Notes: This function creates a lock file in the same directory * as file_to_lock with the name "file_to_lock.lock" * A temporary file ".#lk.<hostname>.pid[.threadid] is used. * This function does nothing for Windoze. */ DOTLOCK create_dotlock( const char *file_to_lock ) { static int initialized; DOTLOCK h; int fd = -1; char pidstr[16]; #if !defined (HAVE_DOSISH_SYSTEM) struct utsname utsbuf; #endif const char *nodename; const char *dirpart; int dirpartlen; if( !initialized ) { atexit( remove_lockfiles ); initialized = 1; } if( !file_to_lock ) return NULL; h = m_alloc_clear( sizeof *h ); if( never_lock ) { h->disable = 1; #ifdef _REENTRANT /* fixme: aquire mutex on all_lockfiles */ #endif h->next = all_lockfiles; all_lockfiles = h; return h; } #if !defined (HAVE_DOSISH_SYSTEM) sprintf( pidstr, "%10d\n", (int)getpid() ); /* fixme: add the hostname to the second line (FQDN or IP addr?) */ /* create a temporary file */ if( uname( &utsbuf ) ) nodename = "unknown"; else nodename = utsbuf.nodename; #ifdef __riscos__ { char *iter = (char *) nodename; for (; iter[0]; iter++) if (iter[0] == '.') iter[0] = '/'; } #endif /* __riscos__ */ if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) { dirpart = EXTSEP_S; dirpartlen = 1; } else { dirpartlen = dirpart - file_to_lock; dirpart = file_to_lock; } #ifdef _REENTRANT /* fixme: aquire mutex on all_lockfiles */ #endif h->next = all_lockfiles; all_lockfiles = h; h->tname = m_alloc( dirpartlen + 6+30+ strlen(nodename) + 11 ); #ifndef __riscos__ sprintf( h->tname, "%.*s/.#lk%p.%s.%d", dirpartlen, dirpart, h, nodename, (int)getpid() ); #else /* __riscos__ */ sprintf( h->tname, "%.*s.lk%p/%s/%d", dirpartlen, dirpart, h, nodename, (int)getpid() ); #endif /* __riscos__ */ do { errno = 0; fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); } while( fd == -1 && errno == EINTR ); if( fd == -1 ) { all_lockfiles = h->next; log_error( "failed to create temporary file `%s': %s\n", h->tname, strerror(errno)); m_free(h->tname); m_free(h); return NULL; } if( write(fd, pidstr, 11 ) != 11 ) { all_lockfiles = h->next; #ifdef _REENTRANT /* release mutex */ #endif log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) ); close(fd); unlink(h->tname); m_free(h->tname); m_free(h); return NULL; } if( close(fd) ) { all_lockfiles = h->next; #ifdef _REENTRANT /* release mutex */ #endif log_error( "error closing `%s': %s\n", h->tname, strerror(errno)); unlink(h->tname); m_free(h->tname); m_free(h); return NULL; } #ifdef _REENTRANT /* release mutex */ #endif #endif h->lockname = m_alloc( strlen(file_to_lock) + 6 ); strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); return h; }
/**************** * 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. * * mode 0: Standard * 1: Make sure that at least one factor is of size qbits. */ MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors ) { int n; /* number of factors */ int m; /* number of primes in pool */ unsigned fbits; /* length of prime factors */ MPI *factors; /* current factors */ MPI *pool; /* pool of primes */ MPI q; /* first prime factor (variable)*/ MPI prime; /* prime test value */ MPI q_factor; /* used for mode 1 */ byte *perms = NULL; int i, j; int count1, count2; unsigned nprime; unsigned req_qbits = qbits; /* the requested q bits size */ MPI val_2 = mpi_alloc_set_ui( 2 ); /* find number of needed prime factors */ for(n=1; (pbits - qbits - 1) / n >= qbits; n++ ) ; n--; if( !n || (mode==1 && n < 2) ) log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits ); 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 = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB ); q = gen_prime( qbits, 0, 0 ); q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL; /* allocate an array to hold the factors + 2 for later usage */ factors = m_alloc_clear( (n+2) * sizeof *factors ); /* make a pool of 3n+5 primes (this is an arbitrary value) */ m = n*3+5; if( mode == 1 ) m += 5; /* need some more for DSA */ if( m < 25 ) m = 25; pool = m_alloc_clear( m * sizeof *pool ); /* permutate over the pool of primes */ count1=count2=0; 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 = m_alloc_clear( m ); for(i=0; i < n; i++ ) { perms[i] = 1; pool[i] = gen_prime( fbits, 0, 0 ); factors[i] = pool[i]; } } else { m_out_of_n( perms, n, m ); for(i=j=0; i < m && j < n ; i++ ) if( perms[i] ) { if( !pool[i] ) pool[i] = gen_prime( fbits, 0, 0 ); factors[j++] = pool[i]; } if( i == n ) { m_free(perms); perms = NULL; progress('!'); goto next_try; /* allocate new primes */ } } 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 ); 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 ); goto next_try; } } else count2 = 0; } while( !(nprime == pbits && check_prime( prime, val_2 )) ); 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 ) fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) ); for(i=0; i < n; i++ ) fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) ); progress('\n'); } if( ret_factors ) { /* caller wants the factors */ *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors); i = 0; if( mode == 1 ) { (*ret_factors)[i++] = mpi_copy( q_factor ); for(; i <= n; i++ ) (*ret_factors)[i] = mpi_copy( factors[i] ); } else { for(; i < n; i++ ) (*ret_factors)[i] = mpi_copy( factors[i] ); } } if( g ) { /* create a generator (start with 3)*/ MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) ); MPI b = mpi_alloc( mpi_get_nlimbs(prime) ); MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) ); if( mode == 1 ) BUG(); /* not yet implemented */ 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: "); mpi_print( stderr, g, 1 ); } else progress('^'); for(i=0; i < n+2; i++ ) { /*fputc('~', stderr);*/ mpi_fdiv_q(tmp, pmin1, factors[i] ); /* (no mpi_pow(), but it is okay to use this with mod prime) */ 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'); m_free( factors ); /* (factors are shallow copies) */ for(i=0; i < m; i++ ) mpi_free( pool[i] ); m_free( pool ); m_free(perms); mpi_free(val_2); mpi_free(q); return prime; }
static int get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ) { int rc; MPI plain_dek = NULL; byte *frame = NULL; unsigned n, nframe; u16 csum, csum2; rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, k->data, sk->skey ); if( rc ) goto leave; frame = mpi_get_buffer( plain_dek, &nframe, NULL ); mpi_free( plain_dek ); plain_dek = NULL; /* Now get the DEK (data encryption key) from the frame * * Old versions encode the DEK in in this format (msb is left): * * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2 * * Later versions encode the DEK like this: * * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes) * * (mpi_get_buffer already removed the leading zero). * * RND are non-zero randow bytes. * A is the cipher algorithm * DEK is the encryption key (session key) with length k * CSUM */ if( DBG_CIPHER ) log_hexdump("DEK frame:", frame, nframe ); n=0; if( n + 7 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( frame[n] == 1 && frame[nframe-1] == 2 ) { log_info(_("old encoding of the DEK is not supported\n")); rc = G10ERR_CIPHER_ALGO; goto leave; } if( frame[n] != 2 ) /* somethink is wrong */ { rc = G10ERR_WRONG_SECKEY; goto leave; } for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ ; n++; /* and the zero byte */ if( n + 4 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } dek->keylen = nframe - (n+1) - 2; dek->algo = frame[n++]; if( dek->algo == CIPHER_ALGO_IDEA ) write_status(STATUS_RSA_OR_IDEA); rc = check_cipher_algo( dek->algo ); if( rc ) { if( !opt.quiet && rc == G10ERR_CIPHER_ALGO ) { log_info(_("cipher algorithm %d is unknown or disabled\n"), dek->algo); } dek->algo = 0; goto leave; } if( (dek->keylen*8) != cipher_get_keylen( dek->algo ) ) { rc = G10ERR_WRONG_SECKEY; goto leave; } /* copy the key to DEK and compare the checksum */ csum = frame[nframe-2] << 8; csum |= frame[nframe-1]; memcpy( dek->key, frame+n, dek->keylen ); for( csum2=0, n=0; n < dek->keylen; n++ ) csum2 += dek->key[n]; if( csum != csum2 ) { rc = G10ERR_WRONG_SECKEY; goto leave; } if( DBG_CIPHER ) log_hexdump("DEK is:", dek->key, dek->keylen ); /* check that the algo is in the preferences and whether it has expired */ { PKT_public_key *pk = m_alloc_clear( sizeof *pk ); if( (rc = get_pubkey( pk, keyid )) ) log_error("public key problem: %s\n", g10_errstr(rc) ); else if( !pk->local_id && query_trust_record(pk) ) log_error("can't check algorithm against preferences\n"); else if( dek->algo != CIPHER_ALGO_3DES && !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, dek->algo ) ) { /* Don't print a note while we are not on verbose mode, * the cipher is blowfish and the preferences have twofish * listed */ if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH || !is_algo_in_prefs( pk->local_id, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH ) ) log_info(_( "NOTE: cipher algorithm %d not found in preferences\n"), dek->algo ); } if( !rc && pk->expiredate && pk->expiredate <= make_timestamp() ) { log_info(_("NOTE: secret key %08lX expired at %s\n"), (ulong)keyid[1], asctimestamp( pk->expiredate) ); } /* FIXME: check wheter the key has been revoked and display * the revocation reason. Actually the user should know this himself, * but the sender might not know already and therefor the user * should get a notice that an revoked key has been used to decode * the message. The user can than watch out for snakes send by * one of those Eves outside his paradise :-) */ free_public_key( pk ); rc = 0; } leave: mpi_free(plain_dek); m_free(frame); return rc; }
int exec_write(struct exec_info **info,const char *program, const char *args_in,const char *name,int writeonly,int binary) { int ret=G10ERR_GENERAL; if(opt.exec_disable && !opt.no_perm_warn) { log_info(_("external program calls are disabled due to unsafe " "options file permissions\n")); return ret; } #if defined(HAVE_GETUID) && defined(HAVE_GETEUID) /* There should be no way to get to this spot while still carrying setuid privs. Just in case, bomb out if we are. */ if(getuid()!=geteuid()) BUG(); #endif if(program==NULL && args_in==NULL) BUG(); *info=m_alloc_clear(sizeof(struct exec_info)); if(name) (*info)->name=m_strdup(name); (*info)->binary=binary; (*info)->writeonly=writeonly; /* Expand the args, if any */ if(args_in && expand_args(*info,args_in)) goto fail; #ifdef EXEC_TEMPFILE_ONLY if(!(*info)->use_temp_files) { log_error(_("this platform requires temp files when calling external " "programs\n")); goto fail; } #else /* !EXEC_TEMPFILE_ONLY */ /* If there are no args, or there are args, but no temp files, we can use fork/exec/pipe */ if(args_in==NULL || (*info)->use_temp_files==0) { int to[2],from[2]; if(pipe(to)==-1) goto fail; if(pipe(from)==-1) { close(to[0]); close(to[1]); goto fail; } if(((*info)->child=fork())==-1) { close(to[0]); close(to[1]); close(from[0]); close(from[1]); goto fail; } if((*info)->child==0) { char *shell=getenv("SHELL"); if(shell==NULL) shell="/bin/sh"; /* I'm the child */ /* If the program isn't going to respond back, they get to keep their stdout/stderr */ if(!(*info)->writeonly) { /* implied close of STDERR */ if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1) _exit(1); /* implied close of STDOUT */ close(from[0]); if(dup2(from[1],STDOUT_FILENO)==-1) _exit(1); } /* implied close of STDIN */ close(to[1]); if(dup2(to[0],STDIN_FILENO)==-1) _exit(1); if(args_in==NULL) { if(DBG_EXTPROG) log_debug("execlp: %s\n",program); execlp(program,program,NULL); } else { if(DBG_EXTPROG) log_debug("execlp: %s -c %s\n",shell,(*info)->command); execlp(shell,shell,"-c",(*info)->command,NULL); } /* If we get this far the exec failed. Clean up and return. */ log_error(_("unable to execute %s \"%s\": %s\n"), args_in==NULL?"program":"shell", args_in==NULL?program:shell, strerror(errno)); /* This mimics the POSIX sh behavior - 127 means "not found" from the shell. */ if(errno==ENOENT) _exit(127); _exit(1); } /* I'm the parent */ close(to[0]); (*info)->tochild=fdopen(to[1],binary?"wb":"w"); if((*info)->tochild==NULL) { close(to[1]); ret=G10ERR_WRITE_FILE; goto fail; } close(from[1]); (*info)->fromchild=iobuf_fdopen(from[0],"r"); if((*info)->fromchild==NULL) { close(from[0]); ret=G10ERR_READ_FILE; goto fail; } /* fd iobufs are cached?! */ iobuf_ioctl((*info)->fromchild,3,1,NULL); return 0; } #endif /* !EXEC_TEMPFILE_ONLY */ if(DBG_EXTPROG) log_debug("using temp file `%s'\n",(*info)->tempfile_in); /* It's not fork/exec/pipe, so create a temp file */ (*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w"); if((*info)->tochild==NULL) { log_error(_("can't create `%s': %s\n"), (*info)->tempfile_in,strerror(errno)); ret=G10ERR_WRITE_FILE; goto fail; } ret=0; fail: return ret; }