2017-10-06 03:21:00 +02:00
# ifdef __linux__
# define _POSIX_C_SOURCE 200112L
# endif
2017-09-24 21:13:16 +02:00
# include <stdio.h>
# include <stdlib.h>
# include <stdint.h>
# 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
2019-02-14 00:07:53 +01:00
# include <sodium/crypto_hash_sha256.h>
2019-01-13 19:41:04 +01:00
# 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"
2017-09-27 20:38:15 +02:00
# include "likely.h"
2017-09-24 21:13:16 +02:00
# include "vec.h"
# 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-02 16:11:23 +02:00
# include "ed25519/ed25519.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
2018-02-22 01:46:06 +01:00
# ifndef _WIN32
# define FSZ "%zu"
# else
# define FSZ "%Iu"
# endif
2017-10-23 06:29:37 +02:00
// additional 0 terminator is added by C
2017-09-24 21:13:16 +02:00
static const char * const pkprefix = " == ed25519v1-public: type0 == \0 \0 " ;
static const char * const skprefix = " == ed25519v1-secret: type0 == \0 \0 " ;
2018-07-09 18:38:41 +02:00
2018-07-06 02:20:51 +02:00
static const char checksumstr [ ] = " .onion checksum " ;
2018-07-09 18:38:41 +02:00
# define checksumstrlen (sizeof(checksumstr) - 1) // 15
2017-09-24 21:13:16 +02:00
2019-02-14 01:07:20 +01:00
// How many times we loop before a reseed
# define DETERMINISTIC_LOOP_COUNT 1<<24
// Argon2 hashed passphrase stretching settings
# define PWHASH_OPSLIMIT 64
# define PWHASH_MEMLIMIT 64 * 1024 * 1024
# define PWHASH_ALG crypto_pwhash_ALG_ARGON2ID13
2017-09-24 21:13:16 +02:00
// output directory
static char * workdir = 0 ;
static size_t workdirlen = 0 ;
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 13:42:58 +02:00
static int yamloutput = 0 ;
2017-10-22 07:07:45 +02:00
static int numwords = 1 ;
2018-07-09 18:38:41 +02:00
static size_t numneedgenerate = 0 ;
2017-09-25 19:49:47 +02:00
static pthread_mutex_t keysgenerated_mutex ;
2017-09-24 21:13:16 +02:00
static volatile size_t keysgenerated = 0 ;
2017-09-25 19:49:47 +02:00
static volatile int endwork = 0 ;
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
static pthread_mutex_t determseed_mutex ;
static u8 determseed [ SEED_LEN ] ;
# endif
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
2018-01-20 16:33:28 +01:00
# include "filters.h"
2017-09-25 22:57:27 +02:00
2017-10-22 02:40:23 +02:00
# ifdef STATISTICS
# define ADDNUMSUCCESS ++st->numsuccess.v
# else
2017-10-22 07:07:45 +02:00
# define ADDNUMSUCCESS do ; while (0)
2017-10-22 02:40:23 +02:00
# endif
2017-09-30 05:40:12 +02:00
// statistics, if enabled
# ifdef STATISTICS
struct statstruct {
union {
2017-10-06 02:25:51 +02:00
u32 v ;
size_t align ;
} numcalc ;
2017-09-30 05:40:12 +02:00
union {
2017-10-06 02:25:51 +02:00
u32 v ;
size_t align ;
} numsuccess ;
2017-10-09 23:41:34 +02:00
union {
u32 v ;
size_t align ;
} numrestart ;
2017-09-30 05:40:12 +02:00
} ;
VEC_STRUCT ( statsvec , struct statstruct ) ;
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-05-31 16:01:33 +02:00
static void onionready ( char * sname , const u8 * secret , const u8 * pubonion )
2017-09-24 21:13:16 +02:00
{
2017-09-25 19:49:47 +02:00
if ( endwork )
2017-09-24 21:13:16 +02:00
return ;
2017-09-25 19:49:47 +02:00
if ( numneedgenerate ) {
pthread_mutex_lock ( & keysgenerated_mutex ) ;
if ( keysgenerated > = numneedgenerate ) {
pthread_mutex_unlock ( & keysgenerated_mutex ) ;
return ;
}
+ + keysgenerated ;
2018-07-09 18:38:41 +02:00
if ( keysgenerated = = numneedgenerate )
2017-09-25 19:49:47 +02:00
endwork = 1 ;
pthread_mutex_unlock ( & keysgenerated_mutex ) ;
}
2019-01-13 19:41:04 +01:00
// Sanity check that the public key matches the private one.
ge_p3 point ;
u8 testpk [ PUBLIC_LEN ] ;
ge_scalarmult_base ( & point , secret ) ;
ge_p3_tobytes ( testpk , & point ) ;
if ( ! memcmp ( testpk , pubonion , PUBLIC_LEN ) )
abort ( ) ;
2018-07-09 18:38:41 +02:00
if ( ! yamloutput ) {
if ( createdir ( sname , 1 ) ! = 0 ) {
pthread_mutex_lock ( & fout_mutex ) ;
fprintf ( stderr , " ERROR: could not create directory for key output \n " ) ;
pthread_mutex_unlock ( & fout_mutex ) ;
2018-07-06 02:20:51 +02:00
return ;
}
2017-09-25 19:49:47 +02:00
2018-07-09 18:38:41 +02:00
strcpy ( & sname [ onionendpos ] , " /hs_ed25519_secret_key " ) ;
writetofile ( sname , secret , FORMATTED_SECRET_LEN , 1 ) ;
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
strcpy ( & sname [ onionendpos ] , " /hs_ed25519_public_key " ) ;
writetofile ( sname , pubonion , FORMATTED_PUBLIC_LEN , 0 ) ;
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
strcpy ( & sname [ onionendpos ] , " /hostname " ) ;
FILE * hfile = fopen ( sname , " w " ) ;
2017-09-30 05:40:12 +02:00
sname [ onionendpos ] = ' \n ' ;
2018-07-09 18:38:41 +02:00
if ( hfile ) {
fwrite ( & sname [ direndpos ] , ONION_LEN + 1 , 1 , hfile ) ;
fclose ( hfile ) ;
}
if ( fout ) {
pthread_mutex_lock ( & fout_mutex ) ;
fwrite ( & sname [ printstartpos ] , printlen , 1 , fout ) ;
fflush ( fout ) ;
pthread_mutex_unlock ( & fout_mutex ) ;
}
} else
yamlout_writekeys ( & sname [ direndpos ] , pubonion , secret ) ;
}
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
union pubonionunion {
u8 raw [ PKPREFIX_SIZE + PUBLIC_LEN + 32 ] ;
struct {
u64 prefix [ 4 ] ;
u64 key [ 4 ] ;
u64 hash [ 4 ] ;
} i ;
} ;
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
static char * makesname ( )
{
char * sname = ( char * ) malloc ( workdirlen + ONION_LEN + 63 + 1 ) ;
if ( ! sname )
abort ( ) ;
if ( workdir )
memcpy ( sname , workdir , workdirlen ) ;
return sname ;
2017-09-24 21:13:16 +02:00
}
// little endian inc
2017-10-23 07:13:13 +02:00
static void addsk32 ( u8 * sk )
2017-09-24 21:13:16 +02:00
{
2017-10-23 07:13:13 +02:00
register unsigned int c = 8 ;
for ( size_t i = 0 ; i < 32 ; + + i ) {
c = ( unsigned int ) sk [ i ] + c ; sk [ i ] = c & 0xFF ; c > > = 8 ;
2017-09-24 21:13:16 +02:00
// unsure if needed
if ( ! c ) break ;
}
}
2017-10-22 07:07:45 +02:00
// 0123 4567 xxxx --3--> 3456 7xxx
// 0123 4567 xxxx --1--> 1234 567x
static inline void shiftpk ( u8 * dst , const u8 * src , size_t sbits )
{
size_t i , sbytes = sbits / 8 ;
sbits % = 8 ;
2017-10-22 07:13:52 +02:00
for ( i = 0 ; i + sbytes < PUBLIC_LEN ; + + i ) {
2018-02-23 01:03:17 +01:00
dst [ i ] = ( u8 ) ( ( src [ i + sbytes ] < < sbits ) |
( src [ i + sbytes + 1 ] > > ( 8 - sbits ) ) ) ;
2017-10-22 07:07:45 +02:00
}
for ( ; i < PUBLIC_LEN ; + + i )
dst [ i ] = 0 ;
}
2017-09-24 21:13:16 +02:00
static void * dowork ( void * task )
{
2018-07-09 18:38:41 +02:00
union pubonionunion pubonion ;
u8 * const pk = & pubonion . raw [ PKPREFIX_SIZE ] ;
u8 secret [ SKPREFIX_SIZE + SECRET_LEN ] ;
u8 * const sk = & secret [ SKPREFIX_SIZE ] ;
2017-09-24 21:13:16 +02:00
u8 seed [ SEED_LEN ] ;
u8 hashsrc [ checksumstrlen + PUBLIC_LEN + 1 ] ;
2017-10-22 07:07:45 +02:00
u8 wpk [ PUBLIC_LEN + 1 ] ;
2017-09-24 21:13:16 +02:00
char * sname ;
2019-03-16 14:51:16 +01:00
size_t i ;
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
struct statstruct * st = ( struct statstruct * ) task ;
# endif
2018-01-20 20:55:45 +01:00
PREFILTER
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
memcpy ( secret , skprefix , SKPREFIX_SIZE ) ;
2017-10-22 13:10:13 +02:00
wpk [ PUBLIC_LEN ] = 0 ;
2017-10-22 07:07:45 +02:00
memset ( & pubonion , 0 , sizeof ( pubonion ) ) ;
2018-07-09 18:38:41 +02:00
memcpy ( pubonion . raw , pkprefix , PKPREFIX_SIZE ) ;
2017-09-29 20:18:41 +02:00
// write version later as it will be overwritten by hash
2017-09-24 23:52:17 +02:00
memcpy ( hashsrc , checksumstr , checksumstrlen ) ;
2017-09-24 21:13:16 +02:00
hashsrc [ checksumstrlen + PUBLIC_LEN ] = 0x03 ; // version
2018-07-09 18:38:41 +02:00
sname = makesname ( ) ;
2017-09-24 21:13:16 +02:00
initseed :
2017-09-24 23:52:17 +02:00
randombytes ( seed , sizeof ( seed ) ) ;
2017-10-23 07:13:13 +02:00
ed25519_seckey_expand ( sk , seed ) ;
2017-10-09 23:41:34 +02:00
# ifdef STATISTICS
+ + st - > numrestart . v ;
# endif
2017-09-24 21:13:16 +02:00
again :
2017-09-27 20:38:15 +02:00
if ( unlikely ( endwork ) )
2017-09-24 21:13:16 +02:00
goto end ;
2017-09-27 01:35:56 +02:00
ed25519_pubkey ( pk , sk ) ;
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
2017-10-06 02:25:51 +02:00
+ + st - > numcalc . v ;
2017-09-30 05:40:12 +02:00
# endif
2017-10-10 03:02:43 +02:00
DOFILTER ( i , pk , {
2017-10-22 07:07:45 +02:00
if ( numwords > 1 ) {
shiftpk ( wpk , pk , filter_len ( i ) ) ;
size_t j ;
for ( int w = 1 ; ; ) {
DOFILTER ( j , wpk , goto secondfind ) ;
2017-10-22 13:10:13 +02:00
goto next ;
2017-10-22 07:07:45 +02:00
secondfind :
if ( + + w > = numwords )
break ;
shiftpk ( wpk , wpk , filter_len ( j ) ) ;
}
}
2017-10-23 07:13:13 +02:00
// sanity check
if ( ( sk [ 0 ] & 248 ) ! = sk [ 0 ] | | ( ( sk [ 31 ] & 63 ) | 64 ) ! = sk [ 31 ] )
goto initseed ;
2017-10-22 07:07:45 +02:00
2017-10-22 02:40:23 +02:00
ADDNUMSUCCESS ;
2017-10-10 03:02:43 +02:00
// calc checksum
memcpy ( & hashsrc [ checksumstrlen ] , pk , PUBLIC_LEN ) ;
FIPS202_SHA3_256 ( hashsrc , sizeof ( hashsrc ) , & pk [ PUBLIC_LEN ] ) ;
// version byte
pk [ PUBLIC_LEN + 2 ] = 0x03 ;
// base32
2018-05-31 16:01:33 +02:00
strcpy ( base32_to ( & sname [ direndpos ] , pk , PUBONION_LEN ) , " .onion " ) ;
2017-10-23 07:13:13 +02:00
onionready ( sname , secret , pubonion . raw ) ;
2019-01-19 14:52:13 +01:00
pk [ PUBLIC_LEN ] = 0 ; // what is this for?
2017-10-10 03:02:43 +02:00
goto initseed ;
} ) ;
2017-10-22 13:10:13 +02:00
next :
2017-10-23 07:13:13 +02:00
addsk32 ( sk ) ;
2017-09-24 21:13:16 +02:00
goto again ;
end :
2017-09-25 19:49:47 +02:00
free ( sname ) ;
2018-01-20 20:55:45 +01:00
POSTFILTER
2018-05-31 16:01:33 +02:00
sodium_memzero ( secret , sizeof ( secret ) ) ;
sodium_memzero ( seed , sizeof ( seed ) ) ;
2017-09-24 21:13:16 +02:00
return 0 ;
}
2019-01-19 15:10:56 +01:00
// in little-endian order, 32 bytes aka 256 bits
2017-10-22 13:35:45 +02:00
static void addsztoscalar32 ( u8 * dst , size_t v )
2017-09-24 21:13:16 +02:00
{
int i ;
u32 c = 0 ;
2017-09-30 22:34:09 +02:00
for ( i = 0 ; i < 32 ; + + i ) {
2017-09-30 05:40:12 +02:00
c + = * dst + ( v & 0xFF ) ; * dst = c & 0xFF ; c > > = 8 ;
2017-09-24 21:13:16 +02:00
v > > = 8 ;
2017-09-30 05:40:12 +02:00
+ + dst ;
2017-09-24 21:13:16 +02:00
}
}
static void * dofastwork ( void * task )
{
2018-07-09 18:38:41 +02:00
union pubonionunion pubonion ;
u8 * const pk = & pubonion . raw [ PKPREFIX_SIZE ] ;
u8 secret [ SKPREFIX_SIZE + SECRET_LEN ] ;
u8 * const sk = & secret [ SKPREFIX_SIZE ] ;
2017-09-24 21:13:16 +02:00
u8 seed [ SEED_LEN ] ;
u8 hashsrc [ checksumstrlen + PUBLIC_LEN + 1 ] ;
2017-10-22 07:07:45 +02:00
u8 wpk [ PUBLIC_LEN + 1 ] ;
2017-09-24 21:13:16 +02:00
ge_p3 ge_public ;
2019-03-16 14:51:16 +01:00
char * sname ;
2017-10-09 23:41:34 +02:00
size_t counter ;
2017-09-24 21:13:16 +02:00
size_t i ;
2019-03-16 14:51:16 +01:00
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
struct statstruct * st = ( struct statstruct * ) task ;
# endif
2019-03-16 14:51:16 +01:00
2018-01-20 20:55:45 +01:00
PREFILTER
2017-09-24 21:13:16 +02:00
2018-07-09 18:38:41 +02:00
memcpy ( secret , skprefix , SKPREFIX_SIZE ) ;
2017-10-22 13:10:13 +02:00
wpk [ PUBLIC_LEN ] = 0 ;
2017-10-22 07:07:45 +02:00
memset ( & pubonion , 0 , sizeof ( pubonion ) ) ;
2018-07-09 18:38:41 +02:00
memcpy ( pubonion . raw , pkprefix , PKPREFIX_SIZE ) ;
2017-09-29 20:18:41 +02:00
// write version later as it will be overwritten by hash
2017-10-23 07:13:13 +02:00
memcpy ( hashsrc , checksumstr , checksumstrlen ) ;
2017-09-24 21:13:16 +02:00
hashsrc [ checksumstrlen + PUBLIC_LEN ] = 0x03 ; // version
2018-07-09 18:38:41 +02:00
sname = makesname ( ) ;
2017-09-24 21:13:16 +02:00
initseed :
2017-10-09 23:41:34 +02:00
# ifdef STATISTICS
+ + st - > numrestart . v ;
# endif
2017-09-24 23:52:17 +02:00
randombytes ( seed , sizeof ( seed ) ) ;
2017-09-27 01:35:56 +02:00
ed25519_seckey_expand ( sk , seed ) ;
2018-07-06 02:20:51 +02:00
2017-09-24 21:13:16 +02:00
ge_scalarmult_base ( & ge_public , sk ) ;
2017-09-24 23:52:17 +02:00
ge_p3_tobytes ( pk , & ge_public ) ;
2018-07-06 02:20:51 +02:00
2017-10-09 23:41:34 +02:00
for ( counter = 0 ; counter < SIZE_MAX - 8 ; counter + = 8 ) {
2017-09-24 21:13:16 +02:00
ge_p1p1 sum ;
2018-07-06 02:20:51 +02:00
2017-09-27 20:38:15 +02:00
if ( unlikely ( endwork ) )
2017-09-24 21:13:16 +02:00
goto end ;
2017-10-10 03:02:43 +02:00
DOFILTER ( i , pk , {
2017-10-22 07:07:45 +02:00
if ( numwords > 1 ) {
shiftpk ( wpk , pk , filter_len ( i ) ) ;
size_t j ;
for ( int w = 1 ; ; ) {
DOFILTER ( j , wpk , goto secondfind ) ;
2017-10-22 13:10:13 +02:00
goto next ;
2017-10-22 07:07:45 +02:00
secondfind :
if ( + + w > = numwords )
break ;
shiftpk ( wpk , wpk , filter_len ( j ) ) ;
}
}
2017-10-10 03:02:43 +02:00
// found!
// update secret key with counter
2017-10-22 13:35:45 +02:00
addsztoscalar32 ( sk , counter ) ;
2017-10-10 03:02:43 +02:00
// sanity check
2017-10-23 07:13:13 +02:00
if ( ( sk [ 0 ] & 248 ) ! = sk [ 0 ] | | ( ( sk [ 31 ] & 63 ) | 64 ) ! = sk [ 31 ] )
2017-10-22 02:40:23 +02:00
goto initseed ;
ADDNUMSUCCESS ;
2017-10-10 03:02:43 +02:00
// calc checksum
memcpy ( & hashsrc [ checksumstrlen ] , pk , PUBLIC_LEN ) ;
FIPS202_SHA3_256 ( hashsrc , sizeof ( hashsrc ) , & pk [ PUBLIC_LEN ] ) ;
// version byte
pk [ PUBLIC_LEN + 2 ] = 0x03 ;
// full name
strcpy ( base32_to ( & sname [ direndpos ] , pk , PUBONION_LEN ) , " .onion " ) ;
onionready ( sname , secret , pubonion . raw ) ;
2019-01-19 14:52:13 +01:00
pk [ PUBLIC_LEN ] = 0 ; // what is this for?
2017-10-10 03:02:43 +02:00
// don't reuse same seed
goto initseed ;
} ) ;
2017-10-22 13:10:13 +02:00
next :
2019-01-19 17:44:35 +01:00
ge_add ( & sum , & ge_public , & ge_eightpoint ) ;
2017-09-24 23:52:17 +02:00
ge_p1p1_to_p3 ( & ge_public , & sum ) ;
ge_p3_tobytes ( pk , & ge_public ) ;
2017-09-30 05:40:12 +02:00
# ifdef STATISTICS
2017-10-06 02:25:51 +02:00
+ + st - > numcalc . v ;
2017-09-30 05:40:12 +02:00
# endif
2017-09-24 21:13:16 +02:00
}
goto initseed ;
end :
2017-09-25 19:49:47 +02:00
free ( sname ) ;
2018-01-20 20:55:45 +01:00
POSTFILTER
2018-05-31 16:01:33 +02:00
sodium_memzero ( secret , sizeof ( secret ) ) ;
sodium_memzero ( seed , sizeof ( seed ) ) ;
2017-09-24 21:13:16 +02:00
return 0 ;
}
2019-01-13 19:41:04 +01:00
# ifdef PASSPHRASE
2019-02-14 00:07:53 +01:00
static void reseedright ( u8 sk [ SECRET_LEN ] )
{
crypto_hash_sha256_state state ;
crypto_hash_sha256_init ( & state ) ;
// old right side
crypto_hash_sha256_update ( & state , & sk [ 32 ] , 32 ) ;
// new random data
randombytes ( & sk [ 32 ] , 32 ) ;
crypto_hash_sha256_update ( & state , & sk [ 32 ] , 32 ) ;
// put result in right side
crypto_hash_sha256_final ( & state , & sk [ 32 ] ) ;
}
2019-01-13 19:41:04 +01:00
static void * dofastworkdeterministic ( void * task )
{
union pubonionunion pubonion ;
u8 * const pk = & pubonion . raw [ PKPREFIX_SIZE ] ;
u8 secret [ SKPREFIX_SIZE + SECRET_LEN ] ;
u8 * const sk = & secret [ SKPREFIX_SIZE ] ;
u8 seed [ SEED_LEN ] ;
u8 hashsrc [ checksumstrlen + PUBLIC_LEN + 1 ] ;
u8 wpk [ PUBLIC_LEN + 1 ] ;
ge_p3 ge_public ;
2019-03-16 14:51:16 +01:00
char * sname ;
2019-01-19 15:10:56 +01:00
size_t counter , oldcounter ;
2019-01-13 19:41:04 +01:00
size_t i ;
2019-03-16 14:51:16 +01:00
2019-01-13 19:41:04 +01:00
# ifdef STATISTICS
struct statstruct * st = ( struct statstruct * ) task ;
# endif
2019-03-16 14:51:16 +01:00
2019-01-13 19:41:04 +01:00
PREFILTER
memcpy ( secret , skprefix , SKPREFIX_SIZE ) ;
wpk [ PUBLIC_LEN ] = 0 ;
memset ( & pubonion , 0 , sizeof ( pubonion ) ) ;
memcpy ( pubonion . raw , pkprefix , PKPREFIX_SIZE ) ;
// write version later as it will be overwritten by hash
memcpy ( hashsrc , checksumstr , checksumstrlen ) ;
hashsrc [ checksumstrlen + PUBLIC_LEN ] = 0x03 ; // version
sname = makesname ( ) ;
initseed :
pthread_mutex_lock ( & determseed_mutex ) ;
for ( int i = 0 ; i < SEED_LEN ; i + + )
if ( + + determseed [ i ] )
break ;
memcpy ( seed , determseed , SEED_LEN ) ;
pthread_mutex_unlock ( & determseed_mutex ) ;
ed25519_seckey_expand ( sk , seed ) ;
2019-02-14 00:07:53 +01:00
2019-01-13 19:41:04 +01:00
# ifdef STATISTICS
+ + st - > numrestart . v ;
# endif
ge_scalarmult_base ( & ge_public , sk ) ;
ge_p3_tobytes ( pk , & ge_public ) ;
2019-01-19 15:10:56 +01:00
for ( counter = oldcounter = 0 ; counter < DETERMINISTIC_LOOP_COUNT ; counter + = 8 ) {
2019-01-13 19:41:04 +01:00
ge_p1p1 sum ;
if ( unlikely ( endwork ) )
goto end ;
DOFILTER ( i , pk , {
if ( numwords > 1 ) {
shiftpk ( wpk , pk , filter_len ( i ) ) ;
size_t j ;
for ( int w = 1 ; ; ) {
DOFILTER ( j , wpk , goto secondfind ) ;
goto next ;
secondfind :
if ( + + w > = numwords )
break ;
shiftpk ( wpk , wpk , filter_len ( j ) ) ;
}
}
// found!
2019-01-19 15:10:56 +01:00
// update secret key with delta since last hit (if any)
addsztoscalar32 ( sk , counter - oldcounter ) ;
oldcounter = counter ;
2019-01-13 19:41:04 +01:00
// sanity check
if ( ( sk [ 0 ] & 248 ) ! = sk [ 0 ] | | ( ( sk [ 31 ] & 63 ) | 64 ) ! = sk [ 31 ] )
goto initseed ;
2019-02-15 21:58:26 +01:00
// reseed right half of key to avoid reuse, it won't change public key anyway
reseedright ( sk ) ;
2019-01-13 19:41:04 +01:00
ADDNUMSUCCESS ;
// calc checksum
memcpy ( & hashsrc [ checksumstrlen ] , pk , PUBLIC_LEN ) ;
FIPS202_SHA3_256 ( hashsrc , sizeof ( hashsrc ) , & pk [ PUBLIC_LEN ] ) ;
// version byte
pk [ PUBLIC_LEN + 2 ] = 0x03 ;
// full name
strcpy ( base32_to ( & sname [ direndpos ] , pk , PUBONION_LEN ) , " .onion " ) ;
onionready ( sname , secret , pubonion . raw ) ;
2019-01-19 14:52:13 +01:00
pk [ PUBLIC_LEN ] = 0 ; // what is this for?
2019-01-13 19:41:04 +01:00
} ) ;
next :
ge_add ( & sum , & ge_public , & ge_eightpoint ) ;
ge_p1p1_to_p3 ( & ge_public , & sum ) ;
ge_p3_tobytes ( pk , & ge_public ) ;
# ifdef STATISTICS
+ + st - > numcalc . v ;
# endif
}
goto initseed ;
end :
free ( sname ) ;
POSTFILTER
sodium_memzero ( secret , sizeof ( secret ) ) ;
sodium_memzero ( seed , sizeof ( seed ) ) ;
return 0 ;
}
2019-01-19 17:44:35 +01:00
# endif // PASSPHRASE
2019-01-19 23:40:15 +01:00
# ifndef BATCHNUM
2019-01-20 01:15:58 +01:00
# define BATCHNUM 2048
2019-01-19 23:40:15 +01:00
# endif
2019-01-19 17:44:35 +01:00
static void * dobatchwork ( void * task )
{
union pubonionunion pubonion ;
u8 * const pk = & pubonion . raw [ PKPREFIX_SIZE ] ;
u8 secret [ SKPREFIX_SIZE + SECRET_LEN ] ;
u8 * const sk = & secret [ SKPREFIX_SIZE ] ;
u8 seed [ SEED_LEN ] ;
u8 hashsrc [ checksumstrlen + PUBLIC_LEN + 1 ] ;
u8 wpk [ PUBLIC_LEN + 1 ] ;
ge_p3 ge_public ;
2019-03-16 14:51:16 +01:00
char * sname ;
2019-01-19 17:44:35 +01:00
ge_p3 ge_batch [ BATCHNUM ] ;
fe * ( batchgez ) [ BATCHNUM ] ;
fe tmp_batch [ BATCHNUM ] ;
bytes32 pk_batch [ BATCHNUM ] ;
size_t counter ;
size_t i ;
2019-03-16 14:51:16 +01:00
2019-01-19 17:44:35 +01:00
# ifdef STATISTICS
struct statstruct * st = ( struct statstruct * ) task ;
# endif
for ( size_t b = 0 ; b < BATCHNUM ; + + b )
2019-01-20 00:29:02 +01:00
batchgez [ b ] = & GEZ ( ge_batch [ b ] ) ;
2019-01-19 17:44:35 +01:00
PREFILTER
memcpy ( secret , skprefix , SKPREFIX_SIZE ) ;
wpk [ PUBLIC_LEN ] = 0 ;
memset ( & pubonion , 0 , sizeof ( pubonion ) ) ;
memcpy ( pubonion . raw , pkprefix , PKPREFIX_SIZE ) ;
// write version later as it will be overwritten by hash
memcpy ( hashsrc , checksumstr , checksumstrlen ) ;
hashsrc [ checksumstrlen + PUBLIC_LEN ] = 0x03 ; // version
sname = makesname ( ) ;
initseed :
# ifdef STATISTICS
+ + st - > numrestart . v ;
# endif
randombytes ( seed , sizeof ( seed ) ) ;
ed25519_seckey_expand ( sk , seed ) ;
ge_scalarmult_base ( & ge_public , sk ) ;
for ( counter = 0 ; counter < SIZE_MAX - ( 8 * BATCHNUM ) ; counter + = 8 * BATCHNUM ) {
ge_p1p1 sum ;
if ( unlikely ( endwork ) )
goto end ;
for ( size_t b = 0 ; b < BATCHNUM ; + + b ) {
ge_batch [ b ] = ge_public ;
ge_add ( & sum , & ge_public , & ge_eightpoint ) ;
ge_p1p1_to_p3 ( & ge_public , & sum ) ;
}
2019-01-20 00:04:48 +01:00
// NOTE: leaves unfinished
ge_p3_batchtobytes_destructive_1 ( pk_batch , ge_batch , batchgez , tmp_batch , BATCHNUM ) ;
2019-01-19 17:44:35 +01:00
# ifdef STATISTICS
st - > numcalc . v + = BATCHNUM ;
2019-01-13 19:41:04 +01:00
# endif
2019-01-19 17:44:35 +01:00
for ( size_t b = 0 ; b < BATCHNUM ; + + b ) {
DOFILTER ( i , pk_batch [ b ] , {
if ( numwords > 1 ) {
shiftpk ( wpk , pk_batch [ b ] , filter_len ( i ) ) ;
size_t j ;
for ( int w = 1 ; ; ) {
DOFILTER ( j , wpk , goto secondfind ) ;
goto next ;
secondfind :
if ( + + w > = numwords )
break ;
shiftpk ( wpk , wpk , filter_len ( j ) ) ;
}
}
// found!
2019-01-20 00:04:48 +01:00
// finish it up
ge_p3_batchtobytes_destructive_finish ( pk_batch [ b ] , & ge_batch [ b ] ) ;
2019-01-19 17:44:35 +01:00
// copy public key
memcpy ( pk , pk_batch [ b ] , PUBLIC_LEN ) ;
// update secret key with counter
addsztoscalar32 ( sk , counter + ( b * 8 ) ) ;
// sanity check
if ( ( sk [ 0 ] & 248 ) ! = sk [ 0 ] | | ( ( sk [ 31 ] & 63 ) | 64 ) ! = sk [ 31 ] )
goto initseed ;
ADDNUMSUCCESS ;
// calc checksum
memcpy ( & hashsrc [ checksumstrlen ] , pk , PUBLIC_LEN ) ;
FIPS202_SHA3_256 ( hashsrc , sizeof ( hashsrc ) , & pk [ PUBLIC_LEN ] ) ;
// version byte
pk [ PUBLIC_LEN + 2 ] = 0x03 ;
// full name
strcpy ( base32_to ( & sname [ direndpos ] , pk , PUBONION_LEN ) , " .onion " ) ;
onionready ( sname , secret , pubonion . raw ) ;
pk [ PUBLIC_LEN ] = 0 ; // what is this for?
// don't reuse same seed
goto initseed ;
} ) ;
next :
;
}
}
goto initseed ;
end :
free ( sname ) ;
POSTFILTER
sodium_memzero ( secret , sizeof ( secret ) ) ;
sodium_memzero ( seed , sizeof ( seed ) ) ;
return 0 ;
}
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 "
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
}
2018-05-31 16:01:33 +02:00
static void e_additional ( )
{
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
static void e_nostatistics ( )
{
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 ) ;
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 ;
const char * hostname = 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 ;
}
2017-10-02 16:11:23 +02:00
ge_initeightpoint ( ) ;
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 ) ;
}
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 ' ) {
if ( argc - - )
loadfilterfile ( * argv + + ) ;
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 ;
2018-07-09 13:42:58 +02:00
hostname = * argv + + ;
2018-07-09 18:38:41 +02:00
if ( ! * hostname )
hostname = 0 ;
if ( hostname & & strlen ( hostname ) ! = ONION_LEN ) {
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 ) ;
}
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
}
}
tret = yamlin_parseandcreate ( fin , sname , hostname ) ;
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-01-19 17:44:35 +01:00
deterministic ? dofastworkdeterministic :
# endif
batchkeygen ? dobatchwork :
2019-01-13 19:41:04 +01:00
( fastkeygen ? dofastwork : dowork ) , 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 ;
}