refactor,fix,rewrite parts,tweak

This commit is contained in:
cathugger 2018-07-09 16:38:41 +00:00
parent 4bdeb62f44
commit be50d6b929
6 changed files with 432 additions and 363 deletions

View File

@ -22,6 +22,7 @@ ED25519OBJ= $(ED25519_@ED25519IMPL@)
MAINOBJ= \
main.c.o \
yaml.c.o \
vec.c.o \
cpucount.c.o \
base32_to.c.o \
@ -394,7 +395,8 @@ main.c.o: ed25519/ed25519-donna/modm-donna-64bit.h
main.c.o: ed25519/ed25519-donna/ed25519-donna-basepoint-table.h
main.c.o: ed25519/ed25519-donna/ed25519-donna-64bit-tables.h
main.c.o: ed25519/ed25519-donna/ed25519-donna-64bit-x86.h
main.c.o: ed25519/ed25519-donna/ed25519-donna-impl-base.h ioutil.h filters.h
main.c.o: ed25519/ed25519-donna/ed25519-donna-impl-base.h ioutil.h common.h
main.c.o: yaml.h filters.h
test_base16.c.o: types.h base16.h
test_base32.c.o: types.h base32.h
test_base64.c.o: types.h base64.h
@ -417,3 +419,4 @@ test_ed25519.c.o: ed25519/ed25519-donna/ed25519-donna-64bit-tables.h
test_ed25519.c.o: ed25519/ed25519-donna/ed25519-donna-64bit-x86.h
test_ed25519.c.o: ed25519/ed25519-donna/ed25519-donna-impl-base.h
vec.c.o: vec.h
yaml.c.o: types.h yaml.h ioutil.h base64.h common.h

22
common.h Normal file
View File

@ -0,0 +1,22 @@
#define SECRET_LEN 64
#define PUBLIC_LEN 32
#define SEED_LEN 32
// with checksum + version num
#define PUBONION_LEN (PUBLIC_LEN + 3)
#define PKPREFIX_SIZE (29 + 3)
#define SKPREFIX_SIZE (29 + 3)
#define FORMATTED_PUBLIC_LEN (PKPREFIX_SIZE + PUBLIC_LEN)
#define FORMATTED_SECRET_LEN (SKPREFIX_SIZE + SECRET_LEN)
// full onion address, WITHOUT newline
#define ONION_LEN 62
extern pthread_mutex_t fout_mutex;
extern FILE *fout;
extern size_t onionendpos; // end of .onion within string
extern size_t direndpos; // end of dir before .onion within string
extern size_t printstartpos; // where to start printing from
extern size_t printlen; // precalculated, related to printstartpos

View File

@ -1,41 +0,0 @@
#define LINEFEED_LEN (sizeof(char))
#define NULLTERM_LEN (sizeof(char))
#define PATH_SEPARATOR_LEN (sizeof(char))
static const int use_secret_mode = 1;
static const int use_public_mode = 0;
static const char hostname_filename[] = "hostname";
static const char secret_key_filename[] = "hs_ed25519_secret_key";
static const char public_key_filename[] = "hs_ed25519_public_key";
static const char keys_field_generated[] = "generated:";
static const char keys_field_hostname[] = " - hostname: ";
static const char keys_field_secretkey[] = " - hs_ed25519_secret_key: ";
static const char keys_field_publickey[] = " - hs_ed25519_public_key: ";
static const char keys_field_time[] = " - time: ";
#define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
#define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
#define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
#define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
#define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
static const char hostname_example[] = "xxxxxvsjzke274nisktdqcl3eqm5ve3m6iur6vwme7m5p6kxivrvjnyd.onion";
static const char seckey_example[] = "PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACwCPMr6rvBRtkW7ZzZ8P7Ne4acRZrhPrN/EF6AETRraFGvdrkW5es4WXB2UxrbuUf8zPoIKkXK5cpdakYdUeM3";
static const char pubkey_example[] = "PT0gZWQyNTUxOXYxLXB1YmxpYzogdHlwZTAgPT0AAAC973vWScqJr/GokqY4CXskGdqTbPIpH1bMJ9nX+VdFYw==";
static const char time_example[] = "2018-07-04 21:31:20";
#define HOSTNAME_LEN (sizeof(hostname_example) - NULLTERM_LEN)
#define SECKEY_LEN (sizeof(seckey_example) - NULLTERM_LEN)
#define PUBKEY_LEN (sizeof(pubkey_example) - NULLTERM_LEN)
#define TIME_LEN (sizeof(time_example) - NULLTERM_LEN)
#define KEYS_LEN ( KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN \
+ KEYS_FIELD_HOSTNAME_LEN + HOSTNAME_LEN + LINEFEED_LEN \
+ KEYS_FIELD_SECRETKEY_LEN + SECKEY_LEN + LINEFEED_LEN \
+ KEYS_FIELD_PUBLICKEY_LEN + PUBKEY_LEN + LINEFEED_LEN \
+ KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
+ LINEFEED_LEN \
)

442
main.c
View File

@ -2,12 +2,10 @@
#define _POSIX_C_SOURCE 200112L
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <signal.h>
#include <sodium/randombytes.h>
@ -17,12 +15,12 @@
#include "likely.h"
#include "vec.h"
#include "base32.h"
#include "base64.h"
#include "cpucount.h"
#include "keccak.h"
#include "ed25519/ed25519.h"
#include "ioutil.h"
#include "constants.h"
#include "common.h"
#include "yaml.h"
#ifndef _WIN32
#define FSZ "%zu"
@ -31,12 +29,11 @@
#endif
// additional 0 terminator is added by C
static const char pkprefix[] = "== ed25519v1-public: type0 ==\0\0";
#define pkprefixlen (sizeof(pkprefix)) // three null-terminators included
static const char skprefix[] = "== ed25519v1-secret: type0 ==\0\0";
#define skprefixlen (sizeof(skprefix)) // three null-terminators included
static const char * const pkprefix = "== ed25519v1-public: type0 ==\0\0";
static const char * const skprefix = "== ed25519v1-secret: type0 ==\0\0";
static const char checksumstr[] = ".onion checksum";
#define checksumstrlen (sizeof(checksumstr) - NULLTERM_LEN)
#define checksumstrlen (sizeof(checksumstr) - 1) // 15
// output directory
static char *workdir = 0;
@ -46,31 +43,25 @@ static int quietflag = 0;
//static int wantdedup = 0;
#define wantdedup 0
#define SECRET_LEN 64
#define PUBLIC_LEN 32
#define SEED_LEN 32
// with checksum + version num
#define PUBONION_LEN (PUBLIC_LEN + 3)
// with newline included
#define ONION_LEN 62
// 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
#define FORMATTED_SECRET_LEN (skprefixlen + SECRET_LEN)
#define FORMATTED_PUBLIC_LEN (pkprefixlen + PUBLIC_LEN)
static size_t onionendpos; // end of .onion within string
static size_t direndpos; // end of dir before .onion within string
static size_t printstartpos; // where to start printing from
static size_t printlen; // precalculated, related to printstartpos
static pthread_mutex_t fout_mutex;
static FILE *fout;
static int yamloutput = 0;
static size_t numneedgenerate = 0;
static int numwords = 1;
static size_t numneedgenerate = 0;
static pthread_mutex_t keysgenerated_mutex;
static volatile size_t keysgenerated = 0;
static volatile int endwork = 0;
pthread_mutex_t fout_mutex;
FILE *fout;
static void termhandler(int sig)
{
switch (sig) {
@ -118,81 +109,6 @@ struct tstatstruct {
VEC_STRUCT(tstatsvec,struct tstatstruct);
#endif
typedef union {
u8 raw[pkprefixlen + PUBLIC_LEN + 32];
struct {
u64 prefix[4];
u64 key[4];
u64 hash[4];
} i;
} pubonionunion;
#define BUF_APPEND(buf,offset,src,srclen) strncpy(&buf[offset],src,srclen); offset += srclen;
#define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
#define BUF_APPEND_CHAR(buf,offet,c) buf[offset++] = c;
static void writekeys(const char *hostname, const u8 *formated_secret, const u8 *formated_public)
{
char keysbuf[KEYS_LEN];
size_t offset = 0;
BUF_APPEND_CSTR(keysbuf, offset, keys_field_generated);
BUF_APPEND_CHAR(keysbuf, offset, '\n');
BUF_APPEND_CSTR(keysbuf, offset, keys_field_hostname);
BUF_APPEND(keysbuf, offset, hostname, ONION_LEN);
BUF_APPEND_CHAR(keysbuf, offset, '\n');
BUF_APPEND_CSTR(keysbuf, offset, keys_field_secretkey);
char seckeybuf[SECKEY_LEN + NULLTERM_LEN];
base64_to(seckeybuf, formated_secret, FORMATTED_SECRET_LEN);
BUF_APPEND(keysbuf, offset, seckeybuf, SECKEY_LEN);
BUF_APPEND_CHAR(keysbuf, offset, '\n');
BUF_APPEND_CSTR(keysbuf, offset, keys_field_publickey);
char pubkeybuf[PUBKEY_LEN + NULLTERM_LEN];
base64_to(pubkeybuf, formated_public, FORMATTED_PUBLIC_LEN);
BUF_APPEND(keysbuf, offset, pubkeybuf, PUBKEY_LEN);
BUF_APPEND_CHAR(keysbuf, offset, '\n');
BUF_APPEND_CSTR(keysbuf, offset, keys_field_time);
char timebuf[TIME_LEN + NULLTERM_LEN];
time_t timer;
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(timebuf, TIME_LEN + NULLTERM_LEN, "%Y-%m-%d %H:%M:%S", tm_info);
BUF_APPEND(keysbuf, offset, timebuf, TIME_LEN);
BUF_APPEND_CHAR(keysbuf, offset, '\n');
BUF_APPEND_CHAR(keysbuf, offset, '\n');
assert(offset == KEYS_LEN);
pthread_mutex_lock(&fout_mutex);
fwrite(keysbuf,sizeof(keysbuf),1,fout);
fflush(fout);
pthread_mutex_unlock(&fout_mutex);
}
#undef BUF_APPEND_CHAR
#undef BUF_APPEND_CSTR
#undef BUF_APPEND
static void printhostname(const char *hostname)
{
char buf[ONION_LEN + LINEFEED_LEN];
strncpy(buf,hostname,ONION_LEN);
buf[ONION_LEN] = '\n';
pthread_mutex_lock(&fout_mutex);
fwrite(buf,sizeof(buf),1,fout);
fflush(fout);
pthread_mutex_unlock(&fout_mutex);
}
static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
{
if (endwork)
@ -204,44 +120,60 @@ static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
pthread_mutex_unlock(&keysgenerated_mutex);
return;
}
}
if (numneedgenerate) {
++keysgenerated;
if (keysgenerated >= numneedgenerate)
if (keysgenerated == numneedgenerate)
endwork = 1;
pthread_mutex_unlock(&keysgenerated_mutex);
}
if (fout) {
if (yamloutput) {
writekeys(&sname[printstartpos],secret,pubonion);
return;
} else {
printhostname(&sname[printstartpos]);
}
}
if (!yamloutput) {
if (createdir(sname,1) != 0) {
if (numneedgenerate)
pthread_mutex_unlock(&keysgenerated_mutex);
pthread_mutex_lock(&fout_mutex);
fprintf(stderr,"ERROR: could not create directory for key output\n");
pthread_mutex_unlock(&fout_mutex);
return;
}
strcpy(&sname[onionendpos],"/hs_ed25519_secret_key");
writetofile(sname,secret,skprefixlen + SECRET_LEN,1);
writetofile(sname,secret,FORMATTED_SECRET_LEN,1);
strcpy(&sname[onionendpos],"/hs_ed25519_public_key");
writetofile(sname,pubonion,FORMATTED_PUBLIC_LEN,0);
strcpy(&sname[onionendpos],"/hostname");
FILE *hfile = fopen(sname,"w");
if (hfile) {
sname[onionendpos] = '\n';
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);
}
strcpy(&sname[onionendpos],"/hs_ed25519_public_key");
writetofile(sname,pubonion,pkprefixlen + PUBLIC_LEN,0);
union pubonionunion {
u8 raw[PKPREFIX_SIZE + PUBLIC_LEN + 32];
struct {
u64 prefix[4];
u64 key[4];
u64 hash[4];
} i;
} ;
static char *makesname()
{
char *sname = (char *) malloc(workdirlen + ONION_LEN + 63 + 1);
if (!sname)
abort();
if (workdir)
memcpy(sname,workdir,workdirlen);
return sname;
}
// little endian inc
@ -271,10 +203,10 @@ static inline void shiftpk(u8 *dst,const u8 *src,size_t sbits)
static void *dowork(void *task)
{
pubonionunion pubonion;
u8 * const pk = &pubonion.raw[pkprefixlen];
u8 secret[skprefixlen + SECRET_LEN];
u8 * const sk = &secret[skprefixlen];
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];
@ -285,19 +217,15 @@ static void *dowork(void *task)
#endif
PREFILTER
memcpy(secret,skprefix,skprefixlen);
memcpy(secret,skprefix,SKPREFIX_SIZE);
wpk[PUBLIC_LEN] = 0;
memset(&pubonion,0,sizeof(pubonion));
memcpy(pubonion.raw,pkprefix,pkprefixlen);
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 = (char *) malloc(workdirlen + ONION_LEN + 63 + 1);
if (!sname)
abort();
if (workdir)
memcpy(sname,workdir,workdirlen);
sname = makesname();
initseed:
randombytes(seed,sizeof(seed));
@ -371,10 +299,10 @@ static void addsztoscalar32(u8 *dst,size_t v)
static void *dofastwork(void *task)
{
pubonionunion pubonion;
u8 * const pk = &pubonion.raw[pkprefixlen];
u8 secret[skprefixlen + SECRET_LEN];
u8 * const sk = &secret[skprefixlen];
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];
@ -387,19 +315,15 @@ static void *dofastwork(void *task)
#endif
PREFILTER
memcpy(secret,skprefix,skprefixlen);
memcpy(secret,skprefix,SKPREFIX_SIZE);
wpk[PUBLIC_LEN] = 0;
memset(&pubonion,0,sizeof(pubonion));
memcpy(pubonion.raw,pkprefix,pkprefixlen);
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 = (char *) malloc(workdirlen + ONION_LEN + 63 + 1);
if (!sname)
abort();
if (workdir)
memcpy(sname,workdir,workdirlen);
sname = makesname();
initseed:
#ifdef STATISTICS
@ -505,6 +429,7 @@ enum {
Q_FAILOPENOUTPUT,
Q_FAILTHREAD,
Q_FAILTIME,
Q_FAILOPENINPUT,
} ;
static void e_additional()
@ -551,173 +476,18 @@ static void setworkdir(const char *wd)
VEC_STRUCT(threadvec, pthread_t);
int parseandcreate(const char *filepath, const char *hostname)
{
if (strlen(hostname) != ONION_LEN) {
fprintf(stderr, "Invalid onion address \"%s\".\n", hostname);
return 1;
}
char buf[16*1024];
memset(buf, 0, sizeof(buf));
FILE *fkeys = fopen(filepath, "r");
if (fkeys == NULL) {
fprintf(stderr, "Cannot open file with keys \"%s\" for reading.\n", filepath);
return 2;
}
int error_number = 1;
size_t readbytes = 0;
while (1) {
const size_t currentread = fread(
buf + readbytes, // Possibly we already partially receive desired onion address
sizeof(buf[0]),
sizeof(buf) - readbytes - NULLTERM_LEN,
fkeys);
if (currentread == 0) {
fprintf(stderr, "Not found desired hostname \"%s\" in file \"%s\".\n", hostname, filepath);
error_number = 3;
break;
}
readbytes += currentread;
buf[readbytes] = '\0';
char *pfound = strstr(buf, hostname);
if (pfound == NULL) {
if (readbytes > ONION_LEN) {
memmove(buf, buf + readbytes - ONION_LEN, ONION_LEN);
readbytes = ONION_LEN;
}
} else { // Got it!
memmove(buf, pfound, readbytes - (pfound - buf));
readbytes -= pfound - buf;
buf[readbytes] = '\0';
char *pendrecord = NULL;
while (1) {
const size_t currentread = fread(
buf + readbytes,
sizeof(buf[0]),
sizeof(buf) - readbytes - NULLTERM_LEN,
fkeys);
readbytes += currentread;
buf[readbytes] = '\0';
pendrecord = strstr(buf, "\n\n");
if (pendrecord != NULL || currentread == 0) {
break;
}
}
if (pendrecord == NULL) {
fprintf(stderr, "Looks like file with keys \"%s\" is incomplete, found hostname but not keys.\n", filepath);
error_number = 4;
break;
}
const char *const pfield_sec_begin = strstr(buf, keys_field_secretkey);
if (pfield_sec_begin == NULL) {
fprintf(stderr, "Cannot find field with secret key within generated section.\n");
error_number = 5;
break;
}
const char *const p_sec_begin = pfield_sec_begin + KEYS_FIELD_SECRETKEY_LEN;
if (pendrecord - p_sec_begin < BASE64_TO_LEN(FORMATTED_SECRET_LEN)) {
fprintf(stderr, "Generated section it too small to keep base64 encoding of secret key.\n");
error_number = 6;
break;
}
char secbuf[FORMATTED_SECRET_LEN];
if (-1 == base64_from((u8*)secbuf, p_sec_begin, BASE64_TO_LEN(FORMATTED_SECRET_LEN))) {
fprintf(stderr, "Invalid base64 encoding of secret key.\n");
error_number = 7;
break;
}
const char *const pfield_pub_begin = strstr(buf, keys_field_publickey);
if (pfield_pub_begin == NULL) {
fprintf(stderr, "Cannot find field with public key within generated section.\n");
error_number = 8;
break;
}
const char *const p_pub_begin = pfield_pub_begin + KEYS_FIELD_PUBLICKEY_LEN;
if (pendrecord - p_pub_begin < BASE64_TO_LEN(KEYS_FIELD_PUBLICKEY_LEN)) {
fprintf(stderr, "Generated section it too small to keep base64 encoding of public key.\n");
error_number = 9;
break;
}
char pubbuf[FORMATTED_PUBLIC_LEN];
if (-1 == base64_from((u8*)pubbuf, p_pub_begin, BASE64_TO_LEN(FORMATTED_PUBLIC_LEN))) {
fprintf(stderr, "Invalid base64 encoding of secret key.\n");
error_number = 10;
break;
}
char pathbuf[1024];
const size_t keys_directory_path_len = workdirlen + strlen(hostname);
if (keys_directory_path_len >= sizeof(pathbuf)) {
fprintf(stderr, "Keys directory path to is too long: %ld, max allowed length is %ld.\n", keys_directory_path_len, sizeof(pathbuf));
error_number = 11;
break;
}
strncpy(pathbuf, workdir, workdirlen);
strncpy(pathbuf + workdirlen, hostname, strlen(hostname));
pathbuf[keys_directory_path_len] = '\0';
if (-1 == createdir(pathbuf, use_secret_mode)) {
fprintf(stderr, "Cannot create directory \"%s\" for key files.\n", pathbuf);
error_number = 12;
break;
}
const size_t secretkey_filepath_len = keys_directory_path_len + PATH_SEPARATOR_LEN + strlen(secret_key_filename);
if (secretkey_filepath_len >= sizeof(pathbuf)) {
fprintf(stderr, "Path to file with secret key is too long %ld, max allowed length is %ld.\n", secretkey_filepath_len, sizeof(pathbuf));
error_number = 13;
break;
}
pathbuf[keys_directory_path_len] = '/';
strncpy(pathbuf + keys_directory_path_len + PATH_SEPARATOR_LEN, secret_key_filename, strlen(secret_key_filename));
pathbuf[secretkey_filepath_len] = '\0';
if (-1 == writetofile(pathbuf, (u8*)secbuf, sizeof(secbuf), use_secret_mode)) {
fprintf(stderr, "Can't write secret key to file \"%s\".\n", pathbuf);
error_number = 14;
break;
}
const size_t publickey_filepath_len = keys_directory_path_len + PATH_SEPARATOR_LEN + strlen(public_key_filename);
if (publickey_filepath_len >= sizeof(pathbuf)) {
fprintf(stderr, "Path to file with public key is too long %ld, max allowed length is %ld.\n", publickey_filepath_len, sizeof(pathbuf));
error_number = 15;
break;
}
pathbuf[keys_directory_path_len] = '/';
strncpy(pathbuf + keys_directory_path_len + PATH_SEPARATOR_LEN, public_key_filename, strlen(public_key_filename));
pathbuf[publickey_filepath_len] = '\0';
if (-1 == writetofile(pathbuf, (u8*)pubbuf, sizeof(pubbuf), use_public_mode)) {
fprintf(stderr, "Can't write public key to file \"%s\".\n", pathbuf);
error_number = 16;
break;
}
pathbuf[keys_directory_path_len] = '\0';
fprintf(stderr, "Keys successfully exported to directory \"%s\".\n", pathbuf);
error_number = 0;
break;
}
}
if (ferror(fkeys) || error_number) {
fprintf(stderr, "Error #%d while parsing generated file \"%s\" or extracting keys.\n", error_number, filepath);
}
fclose(fkeys);
return error_number;
}
int main(int argc,char **argv)
{
const char *outfile = 0;
const char *infile = 0;
const char *hostname = 0;
const char *arg;
int ignoreargs = 0;
int dirnameflag = 0;
int numthreads = 0;
int fastkeygen = 1;
int outfileoverwrite;
int yamlinput = 0;
int outfileoverwrite = 0;
struct threadvec threads;
#ifdef STATISTICS
struct statsvec stats;
@ -732,8 +502,6 @@ int main(int argc,char **argv)
setvbuf(stderr,0,_IONBF,0);
fout = stdout;
pthread_mutex_init(&keysgenerated_mutex,0);
pthread_mutex_init(&fout_mutex,0);
const char *progname = argv[0];
if (argc <= 1) {
@ -857,18 +625,23 @@ int main(int argc,char **argv)
else if (*arg == 'y')
yamloutput = 1;
else if (*arg == 'Y') {
const char *filepath = 0, *hostname = 0;
if (argc--) {
filepath = *argv++;
if (argc--) {
yamlinput = 1;
if (argc) {
--argc;
infile = *argv++;
if (!*infile)
infile = 0;
if (argc) {
--argc;
hostname = *argv++;
return parseandcreate(filepath, hostname);
if (!*hostname)
hostname = 0;
if (hostname && strlen(hostname) != ONION_LEN) {
fprintf(stderr,"bad onion argument length\n");
exit(Q_UNRECOGNISED);
}
}
else
e_additional();
}
else
e_additional();
}
else {
fprintf(stderr,"unrecognised argument: -%c\n",*arg);
@ -889,6 +662,11 @@ int main(int argc,char **argv)
}
}
if (!fout && yamloutput) {
fprintf(stderr,"nil output with yaml mode does not make sense\n");
exit(Q_FAILOPENOUTPUT); // define new err code?
}
filters_prepare();
filters_print();
@ -913,12 +691,41 @@ int main(int argc,char **argv)
if (!dirnameflag) {
printstartpos = direndpos;
printlen = ONION_LEN + 1;
printlen = ONION_LEN + 1; // + '\n'
} else {
printstartpos = 0;
printlen = onionendpos + 1;
printlen = onionendpos + 1; // + '\n'
}
if (yamlinput) {
char *sname = makesname();
FILE *fin = stdin;
if (infile) {
fin = fopen(infile,"r");
if (!fin) {
fprintf(stderr,"failed to open input file\n");
return Q_FAILOPENINPUT;
}
}
tret = yamlin_parseandcreate(fin,sname,hostname);
if (infile) {
fclose(fin);
fin = 0;
}
free(sname);
if (tret)
return tret;
goto done;
}
if (yamloutput)
yamlout_init();
pthread_mutex_init(&keysgenerated_mutex,0);
pthread_mutex_init(&fout_mutex,0);
if (numthreads <= 0) {
numthreads = cpucount();
if (numthreads <= 0)
@ -1061,8 +868,13 @@ int main(int argc,char **argv)
if (!quietflag)
fprintf(stderr," done.\n");
if (yamloutput)
yamlout_clean();
pthread_mutex_destroy(&keysgenerated_mutex);
pthread_mutex_destroy(&fout_mutex);
done:
filters_clean();
if (outfile)

269
yaml.c Normal file
View File

@ -0,0 +1,269 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include "types.h"
#include "yaml.h"
#include "ioutil.h"
#include "base64.h"
#include "common.h"
#define LINEFEED_LEN (sizeof(char))
#define NULLTERM_LEN (sizeof(char))
#define PATH_SEPARATOR_LEN (sizeof(char))
static const char keys_field_generated[] = "---";
static const char keys_field_hostname[] = "hostname: ";
static const char keys_field_publickey[] = "hs_ed25519_public_key: ";
static const char keys_field_secretkey[] = "hs_ed25519_secret_key: ";
static const char keys_field_time[] = "time: ";
#define KEYS_FIELD_GENERATED_LEN (sizeof(keys_field_generated) - NULLTERM_LEN)
#define KEYS_FIELD_HOSTNAME_LEN (sizeof(keys_field_hostname) - NULLTERM_LEN)
#define KEYS_FIELD_PUBLICKEY_LEN (sizeof(keys_field_publickey) - NULLTERM_LEN)
#define KEYS_FIELD_SECRETKEY_LEN (sizeof(keys_field_secretkey) - NULLTERM_LEN)
#define KEYS_FIELD_TIME_LEN (sizeof(keys_field_time) - NULLTERM_LEN)
static const char hostname_example[] = "xxxxxvsjzke274nisktdqcl3eqm5ve3m6iur6vwme7m5p6kxivrvjnyd.onion";
static const char pubkey_example[] = "PT0gZWQyNTUxOXYxLXB1YmxpYzogdHlwZTAgPT0AAAC973vWScqJr/GokqY4CXskGdqTbPIpH1bMJ9nX+VdFYw==";
static const char seckey_example[] = "PT0gZWQyNTUxOXYxLXNlY3JldDogdHlwZTAgPT0AAACwCPMr6rvBRtkW7ZzZ8P7Ne4acRZrhPrN/EF6AETRraFGvdrkW5es4WXB2UxrbuUf8zPoIKkXK5cpdakYdUeM3";
static const char time_example[] = "2018-07-04 21:31:20 Z";
#define HOSTNAME_LEN (sizeof(hostname_example) - NULLTERM_LEN)
#define PUBKEY_LEN (sizeof(pubkey_example) - NULLTERM_LEN)
#define SECKEY_LEN (sizeof(seckey_example) - NULLTERM_LEN)
#define TIME_LEN (sizeof(time_example) - NULLTERM_LEN)
#define KEYS_LEN ( \
KEYS_FIELD_GENERATED_LEN + LINEFEED_LEN + \
KEYS_FIELD_HOSTNAME_LEN + HOSTNAME_LEN + LINEFEED_LEN + \
KEYS_FIELD_PUBLICKEY_LEN + PUBKEY_LEN + LINEFEED_LEN + \
KEYS_FIELD_SECRETKEY_LEN + SECKEY_LEN + LINEFEED_LEN + \
KEYS_FIELD_TIME_LEN + TIME_LEN + LINEFEED_LEN \
)
static pthread_mutex_t tminfo_mutex;
void yamlout_init()
{
pthread_mutex_init(&tminfo_mutex,0);
}
void yamlout_clean()
{
pthread_mutex_destroy(&tminfo_mutex);
}
#define BUF_APPEND(buf,offset,src,srclen) \
do { \
memcpy(&buf[offset],(src),(srclen)); \
offset += (srclen); \
} while (0)
#define BUF_APPEND_CSTR(buf,offset,src) BUF_APPEND(buf,offset,src,strlen(src))
#define BUF_APPEND_CHAR(buf,offset,c) buf[offset++] = (c)
void yamlout_writekeys(const char *hostname,const u8 *formated_public,const u8 *formated_secret)
{
char keysbuf[KEYS_LEN];
char pubkeybuf[PUBKEY_LEN + NULLTERM_LEN];
char seckeybuf[SECKEY_LEN + NULLTERM_LEN];
char timebuf[TIME_LEN + NULLTERM_LEN];
size_t offset = 0;
BUF_APPEND(keysbuf,offset,keys_field_generated,KEYS_FIELD_GENERATED_LEN);
BUF_APPEND_CHAR(keysbuf,offset,'\n');
BUF_APPEND(keysbuf,offset,keys_field_hostname,KEYS_FIELD_HOSTNAME_LEN);
BUF_APPEND(keysbuf,offset,hostname,ONION_LEN);
BUF_APPEND_CHAR(keysbuf,offset,'\n');
BUF_APPEND(keysbuf,offset,keys_field_publickey,KEYS_FIELD_PUBLICKEY_LEN);
base64_to(pubkeybuf,formated_public,FORMATTED_PUBLIC_LEN);
BUF_APPEND(keysbuf,offset,pubkeybuf,PUBKEY_LEN);
BUF_APPEND_CHAR(keysbuf,offset,'\n');
BUF_APPEND(keysbuf,offset,keys_field_secretkey,KEYS_FIELD_SECRETKEY_LEN);
base64_to(seckeybuf,formated_secret,FORMATTED_SECRET_LEN);
BUF_APPEND(keysbuf,offset,seckeybuf,SECKEY_LEN);
BUF_APPEND_CHAR(keysbuf,offset,'\n');
BUF_APPEND(keysbuf,offset,keys_field_time,KEYS_FIELD_TIME_LEN);
time_t currtime;
time(&currtime);
struct tm *tm_info;
pthread_mutex_lock(&tminfo_mutex);
tm_info = gmtime(&currtime);
strftime(timebuf,sizeof(timebuf),"%Y-%m-%d %H:%M:%S Z",tm_info);
pthread_mutex_unlock(&tminfo_mutex);
BUF_APPEND(keysbuf,offset,timebuf,TIME_LEN);
BUF_APPEND_CHAR(keysbuf,offset,'\n');
assert(offset == KEYS_LEN);
pthread_mutex_lock(&fout_mutex);
fwrite(keysbuf,sizeof(keysbuf),1,fout);
fflush(fout);
pthread_mutex_unlock(&fout_mutex);
}
#undef BUF_APPEND_CHAR
#undef BUF_APPEND_CSTR
#undef BUF_APPEND
// pseudo YAML parser
int yamlin_parseandcreate(FILE *fin,char *sname,const char *hostname)
{
char line[256];
size_t len;
u8 pubbuf[FORMATTED_PUBLIC_LEN];
u8 secbuf[FORMATTED_SECRET_LEN];
int hashost = 0,haspub = 0,hassec = 0,skipthis = 0;
enum keytype { HOST, PUB, SEC } keyt;
while (!feof(fin) && !ferror(fin)) {
if (!fgets(line,sizeof(line),fin))
break;
len = strlen(line);
// trim whitespace from the end
while (len != 0 && (line[len-1] == ' ' || line[len-1] == '\n' || line[len-1] == '\r'))
line[--len] = '\0';
// skip empty lines
if (len == 0)
continue;
if (len >= 3 && line[0] == '-' && line[1] == '-' && line[2] == '-') {
// end of document indicator
if (!skipthis && (hashost || haspub || hassec)) {
fprintf(stderr,"ERROR: incomplete record\n");
return 1;
}
hashost = haspub = hassec = skipthis = 0;
continue;
}
if (skipthis)
continue;
char *start = line;
// trim whitespace
while (len != 0 && *start == ' ') {
++start;
--len;
}
// find ':'
char *p = start;
for (;*p != '\0';++p) {
if (*p == ':') {
*p++ = '\0';
goto foundkey;
}
}
// not `key: value`
fprintf(stderr,"ERROR: invalid syntax\n");
return 1; // XXX could continue too there but eh
foundkey:
if (!strcmp(start,"hostname"))
keyt = HOST;
else if (!strcmp(start,"hs_ed25519_public_key"))
keyt = PUB;
else if (!strcmp(start,"hs_ed25519_secret_key"))
keyt = SEC;
else
continue; // uninterested
// skip WS
while (*p == ' ')
++p;
if (*p == '!') {
// skip ! tag
while (*p != '\0' && *p != ' ')
++p;
// skip WS
while (*p == ' ')
++p;
}
len = strlen(p);
switch (keyt) {
case HOST:
if (len != ONION_LEN) {
fprintf(stderr,"ERROR: invalid hostname syntax\n");
return 1;
}
if (!hostname || !strcmp(hostname,p)) {
memcpy(&sname[direndpos],p,len + 1);
hashost = 1;
} else
skipthis = 1;
break;
case PUB:
if (len != PUBKEY_LEN || !base64_valid(p,0)) {
fprintf(stderr,"ERROR: invalid pubkey syntax\n");
return 1;
}
base64_from(pubbuf,p,len);
haspub = 1;
break;
case SEC:
if (len != SECKEY_LEN || !base64_valid(p,0)) {
fprintf(stderr,"ERROR: invalid seckey syntax\n");
return 1;
}
base64_from(secbuf,p,len);
hassec = 1;
break;
}
if (hashost && haspub && hassec) {
if (createdir(sname,1) != 0) {
fprintf(stderr,"ERROR: could not create directory for key output\n");
return 1;
}
strcpy(&sname[onionendpos],"/hs_ed25519_secret_key");
writetofile(sname,secbuf,FORMATTED_SECRET_LEN,1);
strcpy(&sname[onionendpos],"/hs_ed25519_public_key");
writetofile(sname,pubbuf,FORMATTED_PUBLIC_LEN,0);
strcpy(&sname[onionendpos],"/hostname");
FILE *hfile = fopen(sname,"w");
sname[onionendpos] = '\n';
if (hfile) {
fwrite(&sname[direndpos],ONION_LEN + 1,1,hfile);
fclose(hfile);
}
if (fout) {
fwrite(&sname[printstartpos],printlen,1,fout);
fflush(fout);
}
if (hostname)
return 0; // finished
skipthis = 1;
}
}
if (!feof(fin)) {
fprintf(stderr,"error while reading input\n");
return 1;
}
if (hostname) {
fprintf(stderr,"hostname wasn't found in input\n");
return 1;
}
return 0;
}

4
yaml.h Normal file
View File

@ -0,0 +1,4 @@
extern void yamlout_init();
extern void yamlout_clean();
extern void yamlout_writekeys(const char *hostname,const u8 *formated_public,const u8 *formated_secret);
extern int yamlin_parseandcreate(FILE *fin,char *sname,const char *hostname);