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"
2021-12-08 21:14:20 +01:00
# include "likely.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 ;
2021-11-06 02:26:21 +01:00
# ifdef PASSPHRASE
u8 orig_determseed [ SEED_LEN ] ;
const char * checkpointfile = 0 ;
# endif
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
{
2022-05-05 17:36:36 +02:00
// 0 1 2 3 4 5 6 7
// 01234567890123456789012345678901234567890123456789012345678901234567890123456789
2018-04-07 13:59:30 +02:00
fprintf ( out ,
2022-05-05 17:36:36 +02:00
" Usage: %s FILTER [FILTER...] [OPTION] \n "
" %s -f FILTERFILE [OPTION] \n "
2017-09-24 21:13:16 +02:00
" Options: \n "
2022-05-05 17:36:36 +02:00
" -f FILTERFILE specify filter file which contains filters separated \n "
" by newlines \n "
" -D deduplicate filters \n "
" -q do not print diagnostic output to stderr \n "
" -x do not print onion names \n "
" -v print more diagnostic data \n "
" -o FILENAME output onion names to specified file (append) \n "
" -O FILENAME output onion names to specified file (overwrite) \n "
" -F include directory names in onion names output \n "
" -d DIRNAME output directory \n "
" -t NUMTHREADS specify number of threads to utilise \n "
" (default - try detecting CPU core count) \n "
" -j NUMTHREADS same as -t \n "
" -n NUMKEYS specify number of keys (default - 0 - unlimited) \n "
" -N NUMWORDS specify number of words per key (default - 1) \n "
2023-06-09 16:16:46 +02:00
" -Z deprecated, does nothing \n "
" -z deprecated, does nothing \n "
" -B use batching key generation method (current default) \n "
2022-05-05 17:36:36 +02:00
" -s print statistics each 10 seconds \n "
" -S SECONDS print statistics every specified amount of seconds \n "
" -T do not reset statistics counters when printing \n "
" -y output generated keys in YAML format instead of \n "
" dumping them to filesystem \n "
" -Y [FILENAME [host.onion]] \n "
" parse YAML encoded input and extract key(s) to \n "
" filesystem \n "
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
2022-05-05 17:36:36 +02:00
" -p PASSPHRASE use passphrase to initialize the random seed with \n "
" -P same as -p, but takes passphrase from PASSPHRASE \n "
" environment variable \n "
" --checkpoint filename \n "
" load/save checkpoint of progress to specified file \n "
" (requires passphrase) \n "
2019-01-13 19:41:04 +01:00
# endif
2022-05-05 17:36:36 +02:00
" --rawyaml raw (unprefixed) public/secret keys for -y/-Y \n "
" (may be useful for tor controller API) \n "
" -h, --help, --usage print help to stdout and quit \n "
" -V, --version print version information to stdout and exit \n "
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
}
2022-05-05 17:36:36 +02:00
static void printversion ( void )
{
fprintf ( stdout , " mkp224o " VERSION " \n " ) ;
fflush ( stdout ) ;
}
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 " ) ;
}
2021-11-06 02:26:21 +01:00
static void savecheckpoint ( void )
{
2021-12-08 21:14:20 +01:00
u8 checkpoint [ SEED_LEN ] ;
bool carry = 0 ;
pthread_mutex_lock ( & determseed_mutex ) ;
for ( int i = 0 ; i < SEED_LEN ; i + + ) {
checkpoint [ i ] = determseed [ i ] - orig_determseed [ i ] - carry ;
carry = checkpoint [ i ] > determseed [ i ] ;
}
pthread_mutex_unlock ( & determseed_mutex ) ;
2021-11-06 02:26:21 +01:00
2021-12-08 21:14:20 +01:00
if ( syncwrite ( checkpointfile , 1 , checkpoint , SEED_LEN ) < 0 ) {
pthread_mutex_lock ( & fout_mutex ) ;
2022-12-19 17:30:24 +01:00
fprintf ( stderr , " ERROR: could not save checkpoint to \" %s \" \n " , checkpointfile ) ;
2021-12-08 21:14:20 +01:00
pthread_mutex_unlock ( & fout_mutex ) ;
}
}
2021-11-06 02:26:21 +01:00
2021-12-08 21:14:20 +01:00
static volatile int checkpointer_endwork = 0 ;
static void * checkpointworker ( void * arg )
{
( void ) arg ;
struct timespec ts ;
memset ( & ts , 0 , sizeof ( ts ) ) ;
ts . tv_nsec = 100000000 ;
struct timespec nowtime ;
u64 ilasttime , inowtime ;
clock_gettime ( CLOCK_MONOTONIC , & nowtime ) ;
ilasttime = ( 1000000 * ( u64 ) nowtime . tv_sec ) + ( ( u64 ) nowtime . tv_nsec / 1000 ) ;
while ( ! unlikely ( checkpointer_endwork ) ) {
clock_gettime ( CLOCK_MONOTONIC , & nowtime ) ;
inowtime = ( 1000000 * ( u64 ) nowtime . tv_sec ) + ( ( u64 ) nowtime . tv_nsec / 1000 ) ;
2021-12-08 21:22:24 +01:00
if ( ( i64 ) ( inowtime - ilasttime ) > = 300 * 1000000 /* 5 minutes */ ) {
2021-12-08 21:14:20 +01:00
savecheckpoint ( ) ;
ilasttime = inowtime ;
2021-11-06 02:26:21 +01:00
}
}
2021-12-08 21:14:20 +01:00
savecheckpoint ( ) ;
return 0 ;
2021-11-06 02:26:21 +01:00
}
2019-02-16 17:50:26 +01:00
# endif
2021-12-08 21:14:20 +01:00
VEC_STRUCT ( threadvec , pthread_t ) ;
2017-09-24 21:13:16 +02:00
2020-11-21 12:34:25 +01:00
# include "filters_inc.inc.h"
2019-03-16 20:57:29 +01:00
# include "filters_main.inc.h"
2020-11-21 12:34:25 +01:00
enum worker_type {
WT_BATCH ,
} ;
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 ;
2020-11-21 12:34:25 +01:00
enum worker_type wt = WT_BATCH ;
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 ) ;
}
2022-05-05 17:36:36 +02:00
else if ( ! strcmp ( arg , " version " ) ) {
printversion ( ) ;
exit ( 0 ) ;
}
2020-01-17 15:15:56 +01:00
else if ( ! strcmp ( arg , " rawyaml " ) )
yamlraw = 1 ;
2021-11-06 00:27:14 +01:00
# ifdef PASSPHRASE
else if ( ! strcmp ( arg , " checkpoint " ) ) {
if ( argc - - )
checkpointfile = * argv + + ;
else
e_additional ( ) ;
}
# endif // PASSPHRASE
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 ) ;
}
2022-05-05 17:36:36 +02:00
else if ( * arg = = ' V ' ) {
printversion ( ) ;
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 ' )
2023-06-09 16:16:46 +02:00
/* ignored */ ;
2017-09-24 21:13:16 +02:00
else if ( * arg = = ' z ' )
2023-06-09 16:16:46 +02:00
/* ignored */ ;
2019-01-19 17:44:35 +01:00
else if ( * arg = = ' B ' )
2020-11-21 12:34:25 +01:00
wt = WT_BATCH ;
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 ) ;
}
2022-03-15 02:39:18 +01:00
# ifdef PASSPHRASE
2021-12-08 21:14:20 +01:00
if ( checkpointfile & & ! deterministic ) {
fprintf ( stderr , " --checkpoint requires passphrase \n " ) ;
exit ( 1 ) ;
}
2022-03-15 02:39:18 +01:00
# endif
2021-12-08 21:14:20 +01:00
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
2021-11-06 02:26:21 +01:00
if ( deterministic ) {
if ( ! quietflag & & 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 " ) ;
if ( checkpointfile ) {
2021-12-08 21:24:55 +01:00
memcpy ( orig_determseed , determseed , sizeof ( determseed ) ) ;
2021-11-06 02:26:21 +01:00
// Read current checkpoint position if file exists
2021-12-08 21:14:20 +01:00
FILE * checkout = fopen ( checkpointfile , " r " ) ;
2021-11-06 02:26:21 +01:00
if ( checkout ) {
u8 checkpoint [ SEED_LEN ] ;
2021-12-08 21:14:20 +01:00
if ( fread ( checkpoint , 1 , SEED_LEN , checkout ) ! = SEED_LEN ) {
2021-11-06 02:26:21 +01:00
fprintf ( stderr , " failed to read checkpoint file \n " ) ;
exit ( 1 ) ;
}
fclose ( checkout ) ;
// Apply checkpoint to determseed
2023-08-06 04:13:37 +02:00
bool carry = 0 ;
for ( int i = 0 ; i < SEED_LEN ; i + + ) {
determseed [ i ] + = checkpoint [ i ] + carry ;
carry = determseed [ i ] < checkpoint [ i ] ;
}
2021-11-06 02:26:21 +01:00
}
}
}
2019-02-16 17:50:26 +01:00
# 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
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 {
2020-11-22 14:13:50 +01:00
// 256KiB plus whatever batch stuff uses if in batch mode
size_t ss = 256 < < 10 ;
if ( wt = = WT_BATCH )
ss + = worker_batch_memuse ( ) ;
// align to 64KiB
ss = ( ss + ( 64 < < 10 ) - 1 ) & ~ ( ( 64 < < 10 ) - 1 ) ;
//printf("stack size: " FSZ "\n",ss);
tret = pthread_attr_setstacksize ( tattrp , ss ) ;
2018-06-01 15:48:01 +02:00
if ( tret )
perror ( " pthread_attr_setstacksize " ) ;
}
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
2020-11-21 12:34:25 +01:00
tret = pthread_create (
2020-11-23 04:38:56 +01:00
& VEC_BUF ( threads , i ) ,
tattrp ,
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
2020-11-23 04:38:56 +01:00
deterministic
2023-06-09 16:16:46 +02:00
? CRYPTO_NAMESPACE ( worker_batch_pass )
2020-11-23 04:38:56 +01:00
:
2019-01-19 17:44:35 +01:00
# endif
2023-06-09 16:16:46 +02:00
CRYPTO_NAMESPACE ( worker_batch ) ,
2020-11-21 12:34:25 +01:00
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
2018-06-01 15:48:01 +02:00
if ( tattrp ) {
tret = pthread_attr_destroy ( tattrp ) ;
if ( tret )
perror ( " pthread_attr_destroy " ) ;
}
2022-03-15 02:39:18 +01:00
# ifdef PASSPHRASE
2021-12-08 21:14:20 +01:00
pthread_t checkpoint_thread ;
if ( checkpointfile ) {
tret = pthread_create ( & checkpoint_thread , NULL , checkpointworker , NULL ) ;
if ( tret ) {
fprintf ( stderr , " error while making checkpoint thread: %s \n " , strerror ( tret ) ) ;
exit ( 1 ) ;
}
}
# endif
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
2021-12-08 21:14:20 +01:00
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
}
2021-12-08 21:22:24 +01:00
if ( reportdelay & & ( ! ireporttime | | ( i64 ) ( inowtime - ireporttime ) > = ( i64 ) reportdelay ) ) {
2017-09-30 05:40:12 +02:00
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... " ) ;
2021-12-08 21:14:20 +01:00
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 ) ;
2021-12-08 21:14:20 +01:00
# ifdef PASSPHRASE
if ( checkpointfile ) {
checkpointer_endwork = 1 ;
pthread_join ( checkpoint_thread , 0 ) ;
}
# endif
2017-09-30 05:40:12 +02:00
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 ;
}