optional functionality for writing results to the single file and extracting specific keys from it

This commit is contained in:
heios 2018-07-06 01:20:51 +01:00 committed by Alexander Khristoforov
parent 37a1506b18
commit 6a416795b7
7 changed files with 554 additions and 47 deletions

View file

@ -26,10 +26,17 @@ MAINOBJ= \
cpucount.c.o \
base32_to.c.o \
base32_from.c.o \
base64_to.c.o \
base64_from.c.o \
ioutil.c.o \
$(ED25519OBJ) \
keccak.c.o
TEST_BASE64OBJ= \
test_base64.c.o \
base64_to.c.o \
base64_from.c.o
TEST_BASE32OBJ= \
test_base32.c.o \
base32_to.c.o \
@ -48,6 +55,7 @@ TEST_ED25519OBJ= \
ALLO= $(sort \
$(MAINOBJ) \
$(TEST_BASE64OBJ) \
$(TEST_BASE32OBJ) \
$(TEST_BASE16OBJ) \
$(TEST_ED25519OBJ) \
@ -60,7 +68,7 @@ CLEANO= $(filter %.o,$(ALLO))
MAINLIB= -lpthread -lsodium @MAINLIB@
TEST_ED25519LIB= -lsodium
EXE= mkp224o test_base32 test_base16 test_ed25519
EXE= mkp224o test_base64 test_base32 test_base16 test_ed25519
default: mkp224o
@ -69,6 +77,9 @@ all: $(EXE)
mkp224o: $(MAINOBJ)
$(CC) $(LDFLAGS) $(CFLAGS) -o $@.tmp $^ $(MAINLIB) && $(MV) $@.tmp $@
test_base64: $(TEST_BASE64OBJ)
$(CC) $(LDFLAGS) $(CFLAGS) -o $@.tmp $^ && $(MV) $@.tmp $@
test_base32: $(TEST_BASE32OBJ)
$(CC) $(LDFLAGS) $(CFLAGS) -o $@.tmp $^ && $(MV) $@.tmp $@
@ -104,6 +115,8 @@ base16_from.c.o: types.h base16.h
base16_to.c.o: types.h base16.h
base32_from.c.o: types.h base32.h
base32_to.c.o: types.h base32.h
base64_from.c.o: types.h base64.h
base64_to.c.o: types.h base64.h
cpucount.c.o: cpucount.h
ed25519/amd64-51-30k/batch.c.o: ed25519/amd64-51-30k/crypto_sign.h
ed25519/amd64-51-30k/batch.c.o: ed25519/amd64-51-30k/ed25519.h
@ -384,6 +397,7 @@ 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
test_base16.c.o: types.h base16.h
test_base32.c.o: types.h base32.h
test_base64.c.o: types.h base64.h
test_ed25519.c.o: types.h base16.h ed25519/ed25519.h ed25519/ref10/ed25519.h
test_ed25519.c.o: ed25519/ref10/ge.h ed25519/ref10/fe.h
test_ed25519.c.o: ed25519/ref10/crypto_int32.h ed25519/amd64-51-30k/ed25519.h

11
base64.h Normal file
View file

@ -0,0 +1,11 @@
// converts src[0:slen] to base64 string
char *base64_to(char *dst,const u8 *src,size_t slen);
// calculates length needed to store data converted to base64
#define BASE64_TO_LEN(l) (((l + 3 - 1) / 3) * 4)
// converts src string from base64
size_t base64_from(u8 *dst,const char *src,size_t slen);
// calculates length needed to store data converted from base
#define BASE64_FROM_LEN(l) ((l) / 4 * 3)
// validates base32 string and optionally stores length of valid data
// returns 1 if whole string is good, 0 if string contains invalid data
int base64_valid(const char *src,size_t *count);

90
base64_from.c Normal file
View file

@ -0,0 +1,90 @@
#include <stddef.h>
#include <stdint.h>
#include "types.h"
#include "base64.h"
static const u8 base64f[256] = {
//00 01 02 03 04 05 06 07
//08 09 0A 0B 0C 0D 0E 0F
// 0x00..0x3F
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x00
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x08
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x10
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x18
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x20
0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, // 0x28
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, // 0x30
0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x38
// 0x40..0x7F
0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // 0x40
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, // 0x48
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, // 0x50
0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x58
0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, // 0x60
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, // 0x68
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, // 0x70
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0x78
// 0x80..0xBF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xC0..0xFF
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
size_t base64_from(u8 *dst,const char *src,size_t srclen)
{
if (srclen % 4) {
return -1;
} else if (!srclen) {
return 0;
}
size_t dstlen = BASE64_FROM_LEN(srclen);
dstlen -= (src[srclen - 1] == '=');
dstlen -= (src[srclen - 2] == '=');
for (size_t i = 0, j = 0; i < srclen;) {
u32 sixbits[4];
sixbits[0] = base64f[(unsigned char)src[i++]];
sixbits[1] = base64f[(unsigned char)src[i++]];
sixbits[2] = (src[i] == '=' ? (0 & i++) : base64f[(unsigned char)src[i++]]);
sixbits[3] = (src[i] == '=' ? (0 & i++) : base64f[(unsigned char)src[i++]]);
u32 threebytes = 0
| (sixbits[0] << (3 * 6))
| (sixbits[1] << (2 * 6))
| (sixbits[2] << (1 * 6))
| (sixbits[3] << (0 * 6));
if (j < dstlen) dst[j++] = (threebytes >> (2 * 8));
if (j < dstlen) dst[j++] = (threebytes >> (1 * 8)) & 0xff;
if (j < dstlen) dst[j++] = (threebytes >> (0 * 8)) & 0xff;
}
return dstlen;
}
int base64_valid(const char *src,size_t *count)
{
const char *p;
for (p = src;base64f[(u8)*p] != 0xFF;++p)
;
if (count)
*count = (size_t) (p - src);
return !*p;
}

51
base64_to.c Normal file
View file

@ -0,0 +1,51 @@
#include <stddef.h>
#include <stdint.h>
#include "types.h"
#include "base64.h"
static const char base64t[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/',
};
char *base64_to(char *dst,const u8 *src,size_t slen)
{
if (!slen) {
*dst = '\0';
return dst;
}
for(size_t i = 0; i < slen;) {
u32 threebytes = 0;
threebytes |= (i < slen ? (unsigned char)src[i++] : (unsigned char)0) << (2 * 8);
threebytes |= (i < slen ? (unsigned char)src[i++] : (unsigned char)0) << (1 * 8);
threebytes |= (i < slen ? (unsigned char)src[i++] : (unsigned char)0) << (0 * 8);
*dst++ = base64t[(threebytes >> (3 * 6)) & 63];
*dst++ = base64t[(threebytes >> (2 * 6)) & 63];
*dst++ = base64t[(threebytes >> (1 * 6)) & 63];
*dst++ = base64t[(threebytes >> (0 * 6)) & 63];
}
switch (slen % 3) {
case 0 : break;
case 1 : {
*(dst-2) = '=';
*(dst-1) = '=';
break;
}
case 2 : {
*(dst-1) = '=';
break;
}
}
*dst = '\0';
return dst;
}

41
constants.h Normal file
View file

@ -0,0 +1,41 @@
#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 \
)

340
main.c
View file

@ -2,6 +2,7 @@
#define _POSIX_C_SOURCE 200112L
#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -16,10 +17,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"
#ifndef _WIN32
#define FSZ "%zu"
@ -28,12 +31,12 @@
#endif
// additional 0 terminator is added by C
static const char * const pkprefix = "== ed25519v1-public: type0 ==\0\0";
#define pkprefixlen (29 + 3)
static const char * const skprefix = "== ed25519v1-secret: type0 ==\0\0";
#define skprefixlen (29 + 3)
static const char * const checksumstr = ".onion checksum";
#define checksumstrlen 15
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 checksumstr[] = ".onion checksum";
#define checksumstrlen (sizeof(checksumstr) - NULLTERM_LEN)
// output directory
static char *workdir = 0;
@ -49,7 +52,10 @@ static int quietflag = 0;
// with checksum + version num
#define PUBONION_LEN (PUBLIC_LEN + 3)
// with newline included
#define ONIONLEN 62
#define ONION_LEN 62
#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
@ -58,6 +64,7 @@ static size_t printlen; // precalculated, related to printstartpos
static pthread_mutex_t fout_mutex;
static FILE *fout;
const char *outfilekeys = 0;
static size_t numneedgenerate = 0;
static int numwords = 1;
static pthread_mutex_t keysgenerated_mutex;
@ -111,6 +118,80 @@ 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)
{
@ -125,12 +206,6 @@ static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
}
}
if (createdir(sname,1) != 0) {
if (numneedgenerate)
pthread_mutex_unlock(&keysgenerated_mutex);
return;
}
if (numneedgenerate) {
++keysgenerated;
if (keysgenerated >= numneedgenerate)
@ -138,6 +213,21 @@ static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
pthread_mutex_unlock(&keysgenerated_mutex);
}
if (fout) {
if (outfilekeys) {
writekeys(&sname[printstartpos],secret,pubonion);
return;
} else {
printhostname(&sname[printstartpos]);
}
}
if (createdir(sname,1) != 0) {
if (numneedgenerate)
pthread_mutex_unlock(&keysgenerated_mutex);
return;
}
strcpy(&sname[onionendpos],"/hs_ed25519_secret_key");
writetofile(sname,secret,skprefixlen + SECRET_LEN,1);
@ -145,20 +235,13 @@ static void onionready(char *sname,const u8 *secret,const u8 *pubonion)
FILE *hfile = fopen(sname,"w");
if (hfile) {
sname[onionendpos] = '\n';
fwrite(&sname[direndpos],ONIONLEN + 1,1,hfile);
fwrite(&sname[direndpos],ONION_LEN + 1,1,hfile);
fclose(hfile);
}
strcpy(&sname[onionendpos],"/hs_ed25519_public_key");
writetofile(sname,pubonion,pkprefixlen + PUBLIC_LEN,0);
if (fout) {
sname[onionendpos] = '\n';
pthread_mutex_lock(&fout_mutex);
fwrite(&sname[printstartpos],printlen,1,fout);
fflush(fout);
pthread_mutex_unlock(&fout_mutex);
}
}
// little endian inc
@ -188,14 +271,7 @@ static inline void shiftpk(u8 *dst,const u8 *src,size_t sbits)
static void *dowork(void *task)
{
union pubonionunion {
u8 raw[pkprefixlen + PUBLIC_LEN + 32];
struct {
u64 prefix[4];
u64 key[4];
u64 hash[4];
} i;
} pubonion;
pubonionunion pubonion;
u8 * const pk = &pubonion.raw[pkprefixlen];
u8 secret[skprefixlen + SECRET_LEN];
u8 * const sk = &secret[skprefixlen];
@ -217,7 +293,7 @@ static void *dowork(void *task)
memcpy(hashsrc,checksumstr,checksumstrlen);
hashsrc[checksumstrlen + PUBLIC_LEN] = 0x03; // version
sname = (char *) malloc(workdirlen + ONIONLEN + 63 + 1);
sname = (char *) malloc(workdirlen + ONION_LEN + 63 + 1);
if (!sname)
abort();
if (workdir)
@ -295,14 +371,7 @@ static void addsztoscalar32(u8 *dst,size_t v)
static void *dofastwork(void *task)
{
union pubonionunion {
u8 raw[pkprefixlen + PUBLIC_LEN + 32];
struct {
u64 prefix[4];
u64 key[4];
u64 hash[4];
} i;
} pubonion;
pubonionunion pubonion;
u8 * const pk = &pubonion.raw[pkprefixlen];
u8 secret[skprefixlen + SECRET_LEN];
u8 * const sk = &secret[skprefixlen];
@ -326,7 +395,7 @@ static void *dofastwork(void *task)
memcpy(hashsrc,checksumstr,checksumstrlen);
hashsrc[checksumstrlen + PUBLIC_LEN] = 0x03; // version
sname = (char *) malloc(workdirlen + ONIONLEN + 63 + 1);
sname = (char *) malloc(workdirlen + ONION_LEN + 63 + 1);
if (!sname)
abort();
if (workdir)
@ -411,6 +480,8 @@ static void printhelp(FILE *out,const char *progname)
"\t-q - do not print diagnostic output to stderr\n"
"\t-x - do not print onion names\n"
"\t-o filename - output onion names to specified file\n"
"\t-O filename - output onion names with base64 encoded keys to specified file\n"
"\t-i filename host.onion - read file with keys and create directory with keys for specified host\n"
"\t-F - include directory names in onion names output\n"
"\t-d dirname - output directory\n"
"\t-t numthreads - specify number of threads (default - auto)\n"
@ -479,6 +550,164 @@ 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;
@ -561,6 +790,27 @@ int main(int argc,char **argv)
else
e_additional();
}
else if (*arg == 'O') {
if (argc--)
outfilekeys = *argv++;
else
e_additional();
}
else if (*arg == 'i') {
char * filepath = NULL;
char * hostname = NULL;
if (argc--) {
filepath = *argv++;
if (argc--) {
hostname = *argv++;
return parseandcreate(filepath, hostname);
}
else
e_additional();
}
else
e_additional();
}
else if (*arg == 'F')
dirnameflag = 1;
else if (*arg == 'd') {
@ -626,7 +876,13 @@ int main(int argc,char **argv)
filters_add(arg);
}
if (outfile) {
if (outfilekeys) {
fout = fopen(outfilekeys,"a");
if (!fout) {
perror("failed to open output file for keys");
exit(Q_FAILOPENOUTPUT);
}
} else if (outfile) {
fout = fopen(outfile,"w");
if (!fout) {
perror("failed to open output file");
@ -654,11 +910,11 @@ int main(int argc,char **argv)
createdir(workdir,1);
direndpos = workdirlen;
onionendpos = workdirlen + ONIONLEN;
onionendpos = workdirlen + ONION_LEN;
if (!dirnameflag) {
printstartpos = direndpos;
printlen = ONIONLEN + 1;
printlen = ONION_LEN + 1;
} else {
printstartpos = 0;
printlen = onionendpos + 1;

44
test_base64.c Normal file
View file

@ -0,0 +1,44 @@
#include <stddef.h>
#include <stdint.h>
#include "types.h"
#include "base64.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <sodium/randombytes.h>
struct texttestcase {
const char *in;
const char *out;
const char *rev;
} tests0[] = {
{"", "", ""},
{"f", "Zg==", "f"},
{"fo", "Zm8=", "fo"},
{"foo", "Zm9v", "foo"},
{"foob", "Zm9vYg==", "foob"},
{"fooba", "Zm9vYmE=", "fooba"},
{"foobar", "Zm9vYmFy", "foobar"},
};
int main(void)
{
char buf[1024], buf2[1024];
size_t r;
for (size_t i = 0; i < sizeof(tests0)/sizeof(tests0[0]); ++i) {
base64_to(buf, (const u8 *)tests0[i].in, strlen(tests0[i].in));
if (strcmp(buf, tests0[i].out) != 0) {
printf("invalid encoding result: \"%s\" -> encoded as \"%s\", but expected \"%s\".\n",
tests0[i].in, buf, tests0[i].out);
return 1;
}
r = base64_from((u8 *)buf2, buf, strlen(buf));
buf2[r] = '\0';
if (strcmp(buf2, tests0[i].rev) != 0) {
printf("invalid decoding result: encoded \"%s\", decoded as \"%s\", but expected \"%s\".\n",
tests0[i].out, buf2, tests0[i].rev);
return 2;
}
}
return 0;
}