2017-10-06 03:21:00 +02:00
# define _POSIX_C_SOURCE 200112L
2017-09-24 21:13:16 +02:00
# include <stdio.h>
# include <stdlib.h>
2020-05-23 00:30:14 +02:00
# include <errno.h>
2017-09-24 21:13:16 +02:00
# include <stdint.h>
2020-05-22 19:55:37 +02:00
# include <stdbool.h>
2017-09-24 21:13:16 +02:00
# include <string.h>
2018-07-20 19:10:06 +02:00
# include <time.h>
2017-09-24 21:13:16 +02:00
# include <pthread.h>
2017-09-25 19:49:47 +02:00
# include <signal.h>
2018-08-24 20:31:57 +02:00
# include <sodium/core.h>
2017-09-27 20:38:15 +02:00
# include <sodium/randombytes.h>
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
# include <sodium/crypto_pwhash.h>
# endif
2018-05-31 16:01:33 +02:00
# include <sodium/utils.h>
2017-09-24 21:13:16 +02:00
# include "types.h"
# include "vec.h"
2019-03-17 01:23:10 +01:00
# include "base32.h"
2017-10-06 02:14:33 +02:00
# include "cpucount.h"
2017-09-24 21:13:16 +02:00
# include "keccak.h"
2017-10-23 06:12:04 +02:00
# include "ioutil.h"
2018-07-09 18:38:41 +02:00
# include "common.h"
# include "yaml.h"
2017-09-24 21:13:16 +02:00
2019-03-16 20:57:29 +01:00
# include "filters.h"
# include "worker.h"
2018-02-22 01:46:06 +01:00
# ifndef _WIN32
# define FSZ "%zu"
# else
# define FSZ "%Iu"
# endif
2019-02-14 01:07:20 +01:00
// Argon2 hashed passphrase stretching settings
2019-05-06 18:47:47 +02:00
// NOTE: changing these will break compatibility
# define PWHASH_OPSLIMIT 48
2019-02-14 01:07:20 +01:00
# define PWHASH_MEMLIMIT 64 * 1024 * 1024
# define PWHASH_ALG crypto_pwhash_ALG_ARGON2ID13
2017-09-24 21:13:16 +02:00
static int quietflag = 0 ;
2018-09-26 19:54:14 +02:00
static int verboseflag = 0 ;
# ifndef PCRE2FILTER
static int wantdedup = 0 ;
# endif
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
// 0, direndpos, onionendpos
// printstartpos = either 0 or direndpos
// printlen = either onionendpos + 1 or ONION_LEN + 1 (additional 1 is for newline)
size_t onionendpos ; // end of .onion within string
size_t direndpos ; // end of dir before .onion within string
size_t printstartpos ; // where to start printing from
size_t printlen ; // precalculated, related to printstartpos
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
pthread_mutex_t fout_mutex ;
FILE * fout ;
2017-09-25 19:49:47 +02:00
static void termhandler ( int sig )
{
switch ( sig ) {
case SIGTERM :
case SIGINT :
endwork = 1 ;
break ;
}
}
2017-09-24 21:13:16 +02:00
2017-10-22 02:40:23 +02:00
# ifdef STATISTICS
2017-09-30 05:40:12 +02:00
struct tstatstruct {
u64 numcalc ;
u64 numsuccess ;
2017-10-09 23:41:34 +02:00
u64 numrestart ;
2017-09-30 05:40:12 +02:00
u32 oldnumcalc ;
u32 oldnumsuccess ;
2017-10-09 23:41:34 +02:00
u32 oldnumrestart ;
2017-09-30 05:40:12 +02:00
} ;
VEC_STRUCT ( tstatsvec , struct tstatstruct ) ;
# endif
2018-04-07 13:59:30 +02:00
static void printhelp ( FILE * out , const char * progname )
2017-09-24 21:13:16 +02:00
{
2018-04-07 13:59:30 +02:00
fprintf ( out ,
2017-09-24 21:13:16 +02:00
" Usage: %s filter [filter...] [options] \n "
" %s -f filterfile [options] \n "
" Options: \n "
2018-05-31 16:01:33 +02:00
" \t -h - print help to stdout and quit \n "
2018-09-26 19:54:14 +02:00
" \t -f - specify filter file which contains filters separated by newlines \n "
" \t -D - deduplicate filters \n "
2017-09-24 21:13:16 +02:00
" \t -q - do not print diagnostic output to stderr \n "
" \t -x - do not print onion names \n "
2018-09-26 19:54:14 +02:00
" \t -v - print more diagnostic data \n "
2018-07-09 13:42:58 +02:00
" \t -o filename - output onion names to specified file (append) \n "
" \t -O filename - output onion names to specified file (overwrite) \n "
2017-09-24 21:13:16 +02:00
" \t -F - include directory names in onion names output \n "
" \t -d dirname - output directory \n "
2018-12-10 14:21:51 +01:00
" \t -t numthreads - specify number of threads to utilise (default - CPU core count or 1) \n "
2017-09-30 05:40:12 +02:00
" \t -j numthreads - same as -t \n "
2017-09-24 21:13:16 +02:00
" \t -n numkeys - specify number of keys (default - 0 - unlimited) \n "
2017-10-22 07:07:45 +02:00
" \t -N numwords - specify number of words per key (default - 1) \n "
2019-01-27 19:32:25 +01:00
" \t -z - use faster key generation method; this is now default \n "
2017-09-30 14:43:32 +02:00
" \t -Z - use slower key generation method \n "
2019-01-27 19:32:25 +01:00
" \t -B - use batching key generation method (>10x faster than -z, experimental) \n "
2017-09-30 05:40:12 +02:00
" \t -s - print statistics each 10 seconds \n "
" \t -S t - print statistics every specified ammount of seconds \n "
2017-09-30 14:43:32 +02:00
" \t -T - do not reset statistics counters when printing \n "
2018-07-09 19:26:43 +02:00
" \t -y - output generated keys in YAML format instead of dumping them to filesystem \n "
" \t -Y [filename [host.onion]] - parse YAML encoded input and extract key(s) to filesystem \n "
2020-01-17 15:15:56 +01:00
" \t --rawyaml - raw (unprefixed) public/secret keys for -y/-Y (may be useful for tor controller API) \n "
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
" \t -p passphrase - use passphrase to initialize the random seed with \n "
2019-02-16 17:50:26 +01:00
" \t -P - same as -p, but takes passphrase from PASSPHRASE environment variable \n "
2019-01-13 19:41:04 +01:00
# endif
2017-09-24 21:13:16 +02:00
, progname , progname ) ;
2018-04-07 13:59:30 +02:00
fflush ( out ) ;
2017-09-24 21:13:16 +02:00
}
2019-05-14 19:29:27 +02:00
static void e_additional ( void )
2018-05-31 16:01:33 +02:00
{
fprintf ( stderr , " additional argument required \n " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2018-05-31 16:01:33 +02:00
}
# ifndef STATISTICS
2019-05-14 19:29:27 +02:00
static void e_nostatistics ( void )
2018-05-31 16:01:33 +02:00
{
fprintf ( stderr , " statistics support not compiled in \n " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2018-05-31 16:01:33 +02:00
}
# endif
2018-04-07 13:59:30 +02:00
static void setworkdir ( const char * wd )
2017-09-24 21:13:16 +02:00
{
free ( workdir ) ;
size_t l = strlen ( wd ) ;
if ( ! l ) {
workdir = 0 ;
workdirlen = 0 ;
if ( ! quietflag )
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " unset workdir \n " ) ;
2017-09-24 21:13:16 +02:00
return ;
}
2018-02-23 01:03:17 +01:00
unsigned needslash = 0 ;
2017-09-24 21:13:16 +02:00
if ( wd [ l - 1 ] ! = ' / ' )
needslash = 1 ;
2018-06-16 15:22:52 +02:00
char * s = ( char * ) malloc ( l + needslash + 1 ) ;
2017-10-10 03:02:43 +02:00
if ( ! s )
abort ( ) ;
2018-05-31 16:01:33 +02:00
memcpy ( s , wd , l ) ;
2017-09-24 21:13:16 +02:00
if ( needslash )
s [ l + + ] = ' / ' ;
s [ l ] = 0 ;
2018-07-06 02:20:51 +02:00
2017-09-24 21:13:16 +02:00
workdir = s ;
workdirlen = l ;
if ( ! quietflag )
2017-09-30 05:40:12 +02:00
fprintf ( stderr , " set workdir: %s \n " , workdir ) ;
2017-09-24 21:13:16 +02:00
}
2019-02-16 17:50:26 +01:00
# ifdef PASSPHRASE
static void setpassphrase ( const char * pass )
{
static u8 salt [ crypto_pwhash_SALTBYTES ] = { 0 } ;
fprintf ( stderr , " expanding passphrase (may take a while)... " ) ;
if ( crypto_pwhash ( determseed , sizeof ( determseed ) ,
pass , strlen ( pass ) , salt ,
PWHASH_OPSLIMIT , PWHASH_MEMLIMIT , PWHASH_ALG ) ! = 0 )
{
fprintf ( stderr , " out of memory! \n " ) ;
exit ( 1 ) ;
}
fprintf ( stderr , " done. \n " ) ;
}
# endif
2017-09-24 21:13:16 +02:00
VEC_STRUCT ( threadvec , pthread_t ) ;
2019-03-16 20:57:29 +01:00
# include "filters_main.inc.h"
2017-09-30 05:40:12 +02:00
int main ( int argc , char * * argv )
2017-09-24 21:13:16 +02:00
{
2018-05-31 18:14:35 +02:00
const char * outfile = 0 ;
2018-07-09 18:38:41 +02:00
const char * infile = 0 ;
2020-01-17 15:15:56 +01:00
const char * onehostname = 0 ;
2017-09-24 21:13:16 +02:00
const char * arg ;
int ignoreargs = 0 ;
int dirnameflag = 0 ;
int numthreads = 0 ;
2017-09-30 14:43:32 +02:00
int fastkeygen = 1 ;
2019-01-19 17:44:35 +01:00
int batchkeygen = 0 ;
2018-07-09 18:38:41 +02:00
int yamlinput = 0 ;
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
int deterministic = 0 ;
# endif
2018-07-09 18:38:41 +02:00
int outfileoverwrite = 0 ;
2017-09-24 21:13:16 +02:00
struct threadvec threads ;
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
struct statsvec stats ;
struct tstatsvec tstats ;
u64 reportdelay = 0 ;
2017-09-30 14:43:32 +02:00
int realtimestats = 1 ;
2017-09-30 05:46:17 +02:00
# endif
2017-09-24 21:13:16 +02:00
int tret ;
2017-09-27 14:41:59 +02:00
2018-08-24 20:31:57 +02:00
if ( sodium_init ( ) < 0 ) {
fprintf ( stderr , " sodium_init() failed \n " ) ;
return 1 ;
}
2019-03-16 20:57:29 +01:00
worker_init ( ) ;
2017-09-24 21:13:16 +02:00
filters_init ( ) ;
2017-09-27 14:41:59 +02:00
2018-02-22 01:56:31 +01:00
setvbuf ( stderr , 0 , _IONBF , 0 ) ;
2017-09-24 21:13:16 +02:00
fout = stdout ;
const char * progname = argv [ 0 ] ;
2018-05-31 16:01:33 +02:00
if ( argc < = 1 ) {
2018-04-07 13:59:30 +02:00
printhelp ( stderr , progname ) ;
2018-05-31 16:01:33 +02:00
exit ( 1 ) ;
}
argc - - ; argv + + ;
2017-09-24 21:13:16 +02:00
while ( argc - - ) {
arg = * argv + + ;
if ( ! ignoreargs & & * arg = = ' - ' ) {
int numargit = 0 ;
nextarg :
+ + arg ;
+ + numargit ;
if ( * arg = = ' - ' ) {
if ( numargit > 1 ) {
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " unrecognised argument: - \n " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2017-09-24 21:13:16 +02:00
}
+ + arg ;
if ( ! * arg )
ignoreargs = 1 ;
2018-05-31 16:01:33 +02:00
else if ( ! strcmp ( arg , " help " ) | | ! strcmp ( arg , " usage " ) ) {
2018-04-07 13:59:30 +02:00
printhelp ( stdout , progname ) ;
2018-05-31 16:01:33 +02:00
exit ( 0 ) ;
}
2020-01-17 15:15:56 +01:00
else if ( ! strcmp ( arg , " rawyaml " ) )
yamlraw = 1 ;
2017-09-24 21:13:16 +02:00
else {
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " unrecognised argument: --%s \n " , arg ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2017-09-24 21:13:16 +02:00
}
numargit = 0 ;
}
else if ( * arg = = 0 ) {
if ( numargit = = 1 )
ignoreargs = 1 ;
continue ;
}
2018-05-31 16:01:33 +02:00
else if ( * arg = = ' h ' ) {
2018-04-07 13:59:30 +02:00
printhelp ( stdout , progname ) ;
2018-05-31 16:01:33 +02:00
exit ( 0 ) ;
}
2017-09-24 21:13:16 +02:00
else if ( * arg = = ' f ' ) {
2020-05-22 19:55:37 +02:00
if ( argc - - ) {
2020-05-23 00:30:14 +02:00
if ( ! loadfilterfile ( * argv + + ) )
2020-05-22 19:55:37 +02:00
exit ( 1 ) ;
}
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-24 21:13:16 +02:00
}
2018-09-26 19:54:14 +02:00
else if ( * arg = = ' D ' ) {
# ifndef PCRE2FILTER
wantdedup = 1 ;
# else
fprintf ( stderr , " WARNING: deduplication isn't supported with regex filters \n " ) ;
# endif
}
2017-09-24 21:13:16 +02:00
else if ( * arg = = ' q ' )
+ + quietflag ;
else if ( * arg = = ' x ' )
fout = 0 ;
2018-09-26 19:54:14 +02:00
else if ( * arg = = ' v ' )
verboseflag = 1 ;
2017-09-24 21:13:16 +02:00
else if ( * arg = = ' o ' ) {
2018-07-09 13:42:58 +02:00
outfileoverwrite = 0 ;
2017-09-24 21:13:16 +02:00
if ( argc - - )
outfile = * argv + + ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-24 21:13:16 +02:00
}
2018-07-06 02:20:51 +02:00
else if ( * arg = = ' O ' ) {
2018-07-09 13:42:58 +02:00
outfileoverwrite = 1 ;
2017-09-24 21:13:16 +02:00
if ( argc - - )
outfile = * argv + + ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-24 21:13:16 +02:00
}
else if ( * arg = = ' F ' )
dirnameflag = 1 ;
else if ( * arg = = ' d ' ) {
2018-05-31 16:01:33 +02:00
if ( argc - - )
2017-09-24 21:13:16 +02:00
setworkdir ( * argv + + ) ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-24 21:13:16 +02:00
}
2017-09-30 05:40:12 +02:00
else if ( * arg = = ' t ' | | * arg = = ' j ' ) {
2017-09-24 21:13:16 +02:00
if ( argc - - )
numthreads = atoi ( * argv + + ) ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
else if ( * arg = = ' n ' ) {
if ( argc - - )
numneedgenerate = ( size_t ) atoll ( * argv + + ) ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-25 19:49:47 +02:00
}
2017-10-22 07:07:45 +02:00
else if ( * arg = = ' N ' ) {
if ( argc - - )
numwords = atoi ( * argv + + ) ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-10-22 07:07:45 +02:00
}
2017-09-30 14:43:32 +02:00
else if ( * arg = = ' Z ' )
fastkeygen = 0 ;
2017-09-24 21:13:16 +02:00
else if ( * arg = = ' z ' )
fastkeygen = 1 ;
2019-01-19 17:44:35 +01:00
else if ( * arg = = ' B ' )
batchkeygen = 1 ;
2017-09-30 05:40:12 +02:00
else if ( * arg = = ' s ' ) {
# ifdef STATISTICS
reportdelay = 10000000 ;
# else
2018-05-31 16:01:33 +02:00
e_nostatistics ( ) ;
2017-09-30 05:40:12 +02:00
# endif
}
else if ( * arg = = ' S ' ) {
# ifdef STATISTICS
if ( argc - - )
reportdelay = ( u64 ) atoll ( * argv + + ) * 1000000 ;
2018-05-31 16:01:33 +02:00
else
e_additional ( ) ;
2017-09-30 05:40:12 +02:00
# else
2018-05-31 16:01:33 +02:00
e_nostatistics ( ) ;
2017-09-30 05:40:12 +02:00
# endif
}
2017-09-30 14:43:32 +02:00
else if ( * arg = = ' T ' ) {
2017-09-30 05:46:17 +02:00
# ifdef STATISTICS
2017-09-30 14:43:32 +02:00
realtimestats = 0 ;
2017-09-30 05:46:17 +02:00
# else
2018-05-31 16:01:33 +02:00
e_nostatistics ( ) ;
2017-09-30 05:46:17 +02:00
# endif
}
2018-07-09 13:42:58 +02:00
else if ( * arg = = ' y ' )
yamloutput = 1 ;
else if ( * arg = = ' Y ' ) {
2018-07-09 18:38:41 +02:00
yamlinput = 1 ;
if ( argc ) {
- - argc ;
infile = * argv + + ;
if ( ! * infile )
infile = 0 ;
if ( argc ) {
- - argc ;
2020-01-17 15:15:56 +01:00
onehostname = * argv + + ;
if ( ! * onehostname )
onehostname = 0 ;
if ( onehostname & & strlen ( onehostname ) ! = ONION_LEN ) {
2018-07-09 18:38:41 +02:00
fprintf ( stderr , " bad onion argument length \n " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2018-07-09 18:38:41 +02:00
}
2018-07-09 13:42:58 +02:00
}
}
2019-02-16 17:50:26 +01:00
}
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
2019-02-16 17:50:26 +01:00
else if ( * arg = = ' p ' ) {
2019-01-13 19:41:04 +01:00
if ( argc - - ) {
2019-02-16 17:50:26 +01:00
setpassphrase ( * argv + + ) ;
2019-02-14 00:54:00 +01:00
deterministic = 1 ;
2019-02-16 17:50:26 +01:00
}
else
2019-01-13 19:41:04 +01:00
e_additional ( ) ;
2018-07-09 13:42:58 +02:00
}
2019-02-16 17:50:26 +01:00
else if ( * arg = = ' P ' ) {
const char * pass = getenv ( " PASSPHRASE " ) ;
if ( ! pass ) {
fprintf ( stderr , " store passphrase in PASSPHRASE environment variable \n " ) ;
exit ( 1 ) ;
}
setpassphrase ( pass ) ;
deterministic = 1 ;
}
# endif // PASSPHRASE
2017-09-24 21:13:16 +02:00
else {
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " unrecognised argument: -%c \n " , * arg ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2017-09-24 21:13:16 +02:00
}
if ( numargit )
goto nextarg ;
}
2018-05-31 18:14:35 +02:00
else
filters_add ( arg ) ;
}
2020-01-17 15:15:56 +01:00
if ( yamlinput & & yamloutput ) {
fprintf ( stderr , " both -y and -Y does not make sense \n " ) ;
exit ( 1 ) ;
}
if ( yamlraw & & ! yamlinput & & ! yamloutput ) {
fprintf ( stderr , " --rawyaml requires either -y or -Y to do anything \n " ) ;
exit ( 1 ) ;
}
2018-05-31 18:14:35 +02:00
if ( outfile ) {
2018-07-09 13:42:58 +02:00
fout = fopen ( outfile , ! outfileoverwrite ? " a " : " w " ) ;
2018-05-31 18:14:35 +02:00
if ( ! fout ) {
perror ( " failed to open output file " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2018-05-31 18:14:35 +02:00
}
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
if ( ! fout & & yamloutput ) {
fprintf ( stderr , " nil output with yaml mode does not make sense \n " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2018-07-09 18:38:41 +02:00
}
2017-09-24 21:13:16 +02:00
if ( workdir )
2017-10-23 06:12:04 +02:00
createdir ( workdir , 1 ) ;
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
direndpos = workdirlen ;
2018-07-06 02:20:51 +02:00
onionendpos = workdirlen + ONION_LEN ;
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
if ( ! dirnameflag ) {
printstartpos = direndpos ;
2018-07-09 18:38:41 +02:00
printlen = ONION_LEN + 1 ; // + '\n'
2017-09-24 21:13:16 +02:00
} else {
printstartpos = 0 ;
2018-07-09 18:38:41 +02:00
printlen = onionendpos + 1 ; // + '\n'
2017-09-24 21:13:16 +02:00
}
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
if ( yamlinput ) {
char * sname = makesname ( ) ;
FILE * fin = stdin ;
if ( infile ) {
fin = fopen ( infile , " r " ) ;
if ( ! fin ) {
fprintf ( stderr , " failed to open input file \n " ) ;
2018-09-06 23:21:48 +02:00
return 1 ;
2018-07-09 18:38:41 +02:00
}
}
2020-01-17 15:15:56 +01:00
tret = yamlin_parseandcreate ( fin , sname , onehostname , yamlraw ) ;
2018-07-09 18:38:41 +02:00
if ( infile ) {
fclose ( fin ) ;
fin = 0 ;
}
free ( sname ) ;
if ( tret )
return tret ;
goto done ;
}
2017-10-12 03:40:16 +02:00
filters_prepare ( ) ;
filters_print ( ) ;
2017-09-24 21:13:16 +02:00
2017-10-09 23:41:34 +02:00
# ifdef STATISTICS
if ( ! filters_count ( ) & & ! reportdelay )
# else
2017-09-25 22:57:27 +02:00
if ( ! filters_count ( ) )
2017-10-09 23:41:34 +02:00
# endif
2017-09-25 22:57:27 +02:00
return 0 ;
2017-12-14 16:22:45 +01:00
# ifdef EXPANDMASK
if ( numwords > 1 & & flattened )
fprintf ( stderr , " WARNING: -N switch will produce bogus results because we can't know filter width. reconfigure with --enable-besort and recompile. \n " ) ;
# endif
2018-07-09 18:38:41 +02:00
if ( yamloutput )
yamlout_init ( ) ;
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
pthread_mutex_init ( & keysgenerated_mutex , 0 ) ;
2019-02-14 00:07:53 +01:00
pthread_mutex_init ( & fout_mutex , 0 ) ;
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
pthread_mutex_init ( & determseed_mutex , 0 ) ;
# endif
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
if ( numthreads < = 0 ) {
2017-10-06 02:14:33 +02:00
numthreads = cpucount ( ) ;
if ( numthreads < = 0 )
numthreads = 1 ;
2017-09-24 21:13:16 +02:00
}
2018-07-06 00:40:34 +02:00
if ( ! quietflag )
fprintf ( stderr , " using %d %s \n " ,
numthreads , numthreads = = 1 ? " thread " : " threads " ) ;
2017-09-25 19:49:47 +02:00
2019-02-16 17:50:26 +01:00
# ifdef PASSPHRASE
if ( ! quietflag & & deterministic & & numneedgenerate ! = 1 )
fprintf ( stderr , " CAUTION: avoid using keys generated with same password for unrelated services, as single leaked key may help attacker to regenerate related keys. \n " ) ;
# endif
2017-09-30 05:40:12 +02:00
signal ( SIGTERM , termhandler ) ;
signal ( SIGINT , termhandler ) ;
2017-09-25 19:49:47 +02:00
2017-09-24 21:13:16 +02:00
VEC_INIT ( threads ) ;
2017-10-08 20:29:12 +02:00
VEC_ADDN ( threads , numthreads ) ;
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
VEC_INIT ( stats ) ;
2017-10-08 20:29:12 +02:00
VEC_ADDN ( stats , numthreads ) ;
VEC_ZERO ( stats ) ;
2017-09-30 05:40:12 +02:00
VEC_INIT ( tstats ) ;
2017-10-08 20:29:12 +02:00
VEC_ADDN ( tstats , numthreads ) ;
VEC_ZERO ( tstats ) ;
2017-09-30 05:40:12 +02:00
# endif
2017-09-25 19:49:47 +02:00
2019-01-20 01:15:58 +01:00
#if 0
2018-06-01 15:48:01 +02:00
pthread_attr_t tattr , * tattrp = & tattr ;
tret = pthread_attr_init ( tattrp ) ;
if ( tret ) {
perror ( " pthread_attr_init " ) ;
tattrp = 0 ;
}
else {
2018-06-16 14:42:42 +02:00
tret = pthread_attr_setstacksize ( tattrp , 80 < < 10 ) ;
2018-06-01 15:48:01 +02:00
if ( tret )
perror ( " pthread_attr_setstacksize " ) ;
}
2019-01-20 01:15:58 +01:00
# endif
2018-06-01 15:48:01 +02:00
2017-09-30 05:40:12 +02:00
for ( size_t i = 0 ; i < VEC_LENGTH ( threads ) ; + + i ) {
void * tp = 0 ;
# ifdef STATISTICS
tp = & VEC_BUF ( stats , i ) ;
# endif
2019-01-20 01:15:58 +01:00
tret = pthread_create ( & VEC_BUF ( threads , i ) , 0 ,
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
2019-11-15 05:58:21 +01:00
deterministic ? (
batchkeygen ? worker_batch_pass : worker_fast_pass ) :
2019-01-19 17:44:35 +01:00
# endif
2019-03-16 20:57:29 +01:00
batchkeygen ? worker_batch :
( fastkeygen ? worker_fast : worker_slow ) , tp ) ;
2017-09-24 21:13:16 +02:00
if ( tret ) {
2018-06-01 15:48:01 +02:00
fprintf ( stderr , " error while making " FSZ " th thread: %s \n " , i , strerror ( tret ) ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2017-09-24 21:13:16 +02:00
}
}
2017-09-25 19:49:47 +02:00
2019-01-20 01:15:58 +01:00
#if 0
2018-06-01 15:48:01 +02:00
if ( tattrp ) {
tret = pthread_attr_destroy ( tattrp ) ;
if ( tret )
perror ( " pthread_attr_destroy " ) ;
}
2019-01-20 01:15:58 +01:00
# endif
2018-06-01 15:48:01 +02:00
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
struct timespec nowtime ;
u64 istarttime , inowtime , ireporttime = 0 , elapsedoffset = 0 ;
if ( clock_gettime ( CLOCK_MONOTONIC , & nowtime ) < 0 ) {
2018-05-31 16:01:33 +02:00
perror ( " failed to get time " ) ;
2018-09-06 23:21:48 +02:00
exit ( 1 ) ;
2017-09-30 05:40:12 +02:00
}
2018-02-23 01:03:17 +01:00
istarttime = ( 1000000 * ( u64 ) nowtime . tv_sec ) + ( ( u64 ) nowtime . tv_nsec / 1000 ) ;
2017-09-30 05:40:12 +02:00
# endif
2017-09-25 19:49:47 +02:00
struct timespec ts ;
memset ( & ts , 0 , sizeof ( ts ) ) ;
ts . tv_nsec = 100000000 ;
while ( ! endwork ) {
if ( numneedgenerate & & keysgenerated > = numneedgenerate ) {
endwork = 1 ;
break ;
}
nanosleep ( & ts , 0 ) ;
2017-10-09 23:41:34 +02:00
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
clock_gettime ( CLOCK_MONOTONIC , & nowtime ) ;
2018-02-23 01:03:17 +01:00
inowtime = ( 1000000 * ( u64 ) nowtime . tv_sec ) + ( ( u64 ) nowtime . tv_nsec / 1000 ) ;
2017-10-09 23:41:34 +02:00
u64 sumcalc = 0 , sumsuccess = 0 , sumrestart = 0 ;
2018-02-23 00:39:55 +01:00
for ( int i = 0 ; i < numthreads ; + + i ) {
2017-09-30 05:40:12 +02:00
u32 newt , tdiff ;
// numcalc
2017-10-06 02:25:51 +02:00
newt = VEC_BUF ( stats , i ) . numcalc . v ;
2017-09-30 05:40:12 +02:00
tdiff = newt - VEC_BUF ( tstats , i ) . oldnumcalc ;
VEC_BUF ( tstats , i ) . oldnumcalc = newt ;
VEC_BUF ( tstats , i ) . numcalc + = ( u64 ) tdiff ;
sumcalc + = VEC_BUF ( tstats , i ) . numcalc ;
// numsuccess
2017-10-06 02:25:51 +02:00
newt = VEC_BUF ( stats , i ) . numsuccess . v ;
2017-09-30 05:40:12 +02:00
tdiff = newt - VEC_BUF ( tstats , i ) . oldnumsuccess ;
VEC_BUF ( tstats , i ) . oldnumsuccess = newt ;
VEC_BUF ( tstats , i ) . numsuccess + = ( u64 ) tdiff ;
sumsuccess + = VEC_BUF ( tstats , i ) . numsuccess ;
2017-10-09 23:41:34 +02:00
// numrestart
newt = VEC_BUF ( stats , i ) . numrestart . v ;
tdiff = newt - VEC_BUF ( tstats , i ) . oldnumrestart ;
VEC_BUF ( tstats , i ) . oldnumrestart = newt ;
VEC_BUF ( tstats , i ) . numrestart + = ( u64 ) tdiff ;
sumrestart + = VEC_BUF ( tstats , i ) . numrestart ;
2017-09-30 05:40:12 +02:00
}
if ( reportdelay & & ( ! ireporttime | | inowtime - ireporttime > = reportdelay ) ) {
if ( ireporttime )
ireporttime + = reportdelay ;
else
ireporttime = inowtime ;
if ( ! ireporttime )
ireporttime = 1 ;
double calcpersec = ( 1000000.0 * sumcalc ) / ( inowtime - istarttime ) ;
2017-10-09 23:41:34 +02:00
double succpersec = ( 1000000.0 * sumsuccess ) / ( inowtime - istarttime ) ;
double restpersec = ( 1000000.0 * sumrestart ) / ( inowtime - istarttime ) ;
fprintf ( stderr , " >calc/sec:%8lf, succ/sec:%8lf, rest/sec:%8lf, elapsed:%5.6lfsec \n " ,
calcpersec , succpersec , restpersec ,
( inowtime - istarttime + elapsedoffset ) / 1000000.0 ) ;
2017-09-30 05:40:12 +02:00
if ( realtimestats ) {
2018-02-23 00:39:55 +01:00
for ( int i = 0 ; i < numthreads ; + + i ) {
2017-09-30 05:40:12 +02:00
VEC_BUF ( tstats , i ) . numcalc = 0 ;
VEC_BUF ( tstats , i ) . numsuccess = 0 ;
2017-10-09 23:41:34 +02:00
VEC_BUF ( tstats , i ) . numrestart = 0 ;
2017-09-30 05:40:12 +02:00
}
elapsedoffset + = inowtime - istarttime ;
istarttime = inowtime ;
}
}
if ( sumcalc > U64_MAX / 2 ) {
2018-02-23 00:39:55 +01:00
for ( int i = 0 ; i < numthreads ; + + i ) {
2017-09-30 05:40:12 +02:00
VEC_BUF ( tstats , i ) . numcalc / = 2 ;
VEC_BUF ( tstats , i ) . numsuccess / = 2 ;
2017-10-09 23:41:34 +02:00
VEC_BUF ( tstats , i ) . numrestart / = 2 ;
2017-09-30 05:40:12 +02:00
}
u64 timediff = ( inowtime - istarttime + 1 ) / 2 ;
elapsedoffset + = timediff ;
istarttime + = timediff ;
}
# endif
2017-09-25 19:49:47 +02:00
}
2017-09-30 05:40:12 +02:00
if ( ! quietflag )
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " waiting for threads to finish... " ) ;
2017-09-30 05:40:12 +02:00
for ( size_t i = 0 ; i < VEC_LENGTH ( threads ) ; + + i )
pthread_join ( VEC_BUF ( threads , i ) , 0 ) ;
if ( ! quietflag )
2018-05-31 16:01:33 +02:00
fprintf ( stderr , " done. \n " ) ;
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
if ( yamloutput )
yamlout_clean ( ) ;
2019-01-18 20:07:54 +01:00
# ifdef PASSPHRASE
2019-02-14 00:07:53 +01:00
pthread_mutex_destroy ( & determseed_mutex ) ;
2019-01-18 20:07:54 +01:00
# endif
2019-02-14 00:07:53 +01:00
pthread_mutex_destroy ( & fout_mutex ) ;
pthread_mutex_destroy ( & keysgenerated_mutex ) ;
2018-07-09 18:38:41 +02:00
done :
2017-09-24 21:13:16 +02:00
filters_clean ( ) ;
2017-09-25 19:49:47 +02:00
if ( outfile )
fclose ( fout ) ;
2017-09-24 21:13:16 +02:00
return 0 ;
}