From b64264dcf365fc9133e8861883b4d7f6d27bc0c3 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Sun, 5 Jan 2014 04:57:44 +0000 Subject: [PATCH 1/1] Add some initial code --- .gitignore | 6 ++ hmac.c | 29 +++++++ main.c | 210 +++++++++++++++++++++++++++++++++++++++++++++ main.h | 0 makefile | 21 +++++ none.c | 17 ++++ none.h | 4 + scrypt.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++++++ scrypt.h | 3 + sha2.c | 49 +++++++++++ sha2.h | 3 + util.c | 98 +++++++++++++++++++++ util.h | 17 ++++ 13 files changed, 702 insertions(+) create mode 100644 .gitignore create mode 100644 hmac.c create mode 100644 main.c create mode 100644 main.h create mode 100644 makefile create mode 100644 none.c create mode 100644 none.h create mode 100644 scrypt.c create mode 100644 scrypt.h create mode 100644 sha2.c create mode 100644 sha2.h create mode 100644 util.c create mode 100644 util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0441756 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.o +*.swp +*.txt +crypt +tags diff --git a/hmac.c b/hmac.c new file mode 100644 index 0000000..20d097b --- /dev/null +++ b/hmac.c @@ -0,0 +1,29 @@ +/* HMAC */ +static void hmac_gen(hash_t hash, int iter, + const char *out, int nout, + const char *msg, int nmsg, + const char *pass, int npass, + const char *salt, int nsalt); +{ + // iter - ?? + + uint8_t *opad = alloc0(nout); + uint8_t *ipad = alloc0(nout); + uint8_t *buf = alloc0(nout); + uint8_t *tmp1 = alloc0(nout+nmsg); + uint8_t *tmp2 = alloc0(nout+2); + + if (npass > nout) + hash(buf, key); + else if (npass < nout) + memcpy(buf, key, npass); + + for (int i = 0; i < nout; i++) { + opad[i] = 0x5c ^ key[i]; + ipad[i] = 0x36 ^ key[i]; + } + + memcpy(tmp1, ipad, message); + hash(tmp, ipad + message); + hash(out, opad + tmp) +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..5545cff --- /dev/null +++ b/main.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include + +#include + +#include "util.h" + +#include "none.h" +#include "sha2.h" +#include "scrypt.h" + +/* Options */ +#define OPT(flag, opt, name, desc) \ + { name "\0" desc, flag, NULL, opt } + +#define OPT_OPT(opt) ((opt).val) +#define OPT_LEN(opt) ((int)strlen((opt).name)) +#define OPT_NAME(opt) ((opt).name) +#define OPT_DESC(opt) (&(opt).name[OPT_LEN(opt)]) + +/* Crypto functions */ +typedef enum { + NONE, + SHA256, + SCRYPT, +} crypt_t; + +/* Options */ +static struct option long_options[] = { + OPT( 0, 'e', "encrypt", "Encrypt data" ), + OPT( 0, 'd', "decrypt", "Decrypt data" ), + OPT( 0, 't', "test", "Run self tests" ), + OPT( 1, 'f', "function", "Specify crypto function" ), + OPT( 1, 'i', "input", "Input file" ), + OPT( 1, 'o', "output", "Output file" ), + OPT( 0, 'q', "quiet", "Decrease verbosity" ), + OPT( 0, 'v', "verbose", "Increase verbosity" ), + OPT( 0, 'h', "help", "Print usage information" ), + { }, +}; + +static struct { + const char *name; + const char *desc; +} crypt_info[] = { + [NONE ] { "none", "No-op encryption/decryption" }, + [SHA256] { "sha256", "SHA-256 hash function" }, + [SCRYPT] { "scrypt", "Memory intensive hash function" }, +}; + +/* Settings */ +static int opt_decrypt; +static int opt_encrypt; +static crypt_t opt_crypt; +static char *opt_instr; +static char *opt_outstr; +static FILE *opt_input; +static FILE *opt_output; +static int opt_level; +static int opt_test; + +/* Helpers */ +static const char *crypt_name(crypt_t id) +{ + if (id < 0 || id >= N_ELEM(crypt_info)) + error("invalid crypt id %d", id); + return crypt_info[id].name; +} + +static crypt_t crypt_id(const char *name) +{ + for (int i = 0; i < N_ELEM(crypt_info); i++) + if (!strcmp(name, crypt_info[i].name)) + return (crypt_t)i; + error("invalid crypt function %s", name); + return NONE; +} + +static void usage(const char *name) +{ + printf("Usage:\n"); + printf(" %s [OPTION...]\n", name); + printf("\n"); + printf("Options:\n"); + for (int i = 0; long_options[i].name; i++) + printf(" -%c, --%-10s %s\n", + long_options[i].val, + long_options[i].name, + long_options[i].name + 1 + + strlen(long_options[i].name)); + printf("\n"); + printf("Crypto functions:\n"); + for (int i = 0; i < N_ELEM(crypt_info); i++) + printf(" %-16s %s\n", + crypt_info[i].name, + crypt_info[i].desc); +} + +static void parse(int argc, char **argv) +{ + while (1) { + int c = getopt_long(argc, argv, "edf:i:o:qvth", long_options, NULL); + if (c == -1) + break; + switch (c) { + case 'e': + opt_encrypt = 1; + break; + case 'd': + opt_decrypt = 1; + break; + case 't': + opt_test = 1; + break; + case 'f': + opt_crypt = crypt_id(optarg); + break; + case 'i': + opt_input = fopen(optarg, "rb"); + opt_instr = optarg; + break; + case 'o': + opt_output = fopen(optarg, "wb+"); + opt_outstr = optarg; + break; + case 'q': + opt_level--; + break; + case 'v': + opt_level++; + break; + case 'h': + usage(argv[0]); + exit(0); + case '?': + exit(1); + default: + exit(2); + } + } +} + +void run(crypt_t id, FILE *in, FILE *out) +{ + uint8_t dec[512], enc[512]; + uint8_t sum[512]; + int len; + + switch (id) { + case NONE: + while ((len = fread(&dec, 1, 512, in)) > 0) { + //debug("<< [%s]:%d", dec, len); + none_enc(dec, enc, len); + //debug(">> [%s]:%d", enc, len); + fwrite(enc, 1, len, out); + } + break; + case SHA256: + break; + case SCRYPT: + while ((len = fread(&dec, 1, 512, in)) > 0) { + scrypt_hash(dec, sum); + } + break; + } +} + +/* Test */ +static void test(crypt_t id) +{ + if (!opt_test) + return; + + switch (id) { + case NONE: none_test(); break; + case SHA256: sha256_test(); break; + case SCRYPT: scrypt_test(); break; + } +} + +/* Main */ +int main(int argc, char **argv) +{ + /* Parse arguments */ + opt_instr = "stdin"; + opt_outstr = "stdout"; + opt_input = stdin; + opt_output = stdout; + parse(argc, argv); + loglevel = opt_level; + + /* Debug output */ + debug("encrypt: %s", opt_encrypt ? "true" : "false"); + debug("decrypt: %s", opt_decrypt ? "true" : "false"); + debug("crypto: %s", crypt_name(opt_crypt)); + debug("loglevel: %d", opt_level); + debug("input: %s", opt_instr); + debug("output: %s", opt_outstr); + + /* Run tests */ + test(opt_crypt); + + /* Main loop */ + run(opt_crypt, opt_input, opt_output); + + return 0; +}; + diff --git a/main.h b/main.h new file mode 100644 index 0000000..e69de29 diff --git a/makefile b/makefile new file mode 100644 index 0000000..4a3ba25 --- /dev/null +++ b/makefile @@ -0,0 +1,21 @@ +PROG ?= crypt +GCC ?= gcc +CFLAGS ?= -Wall -Werror --std=c99 +CPPFLAGS ?= +LDFLAGS ?= -lfitz + +# Targets +test: $(PROG) + echo test | ./$(PROG) -v -t -f scrypt + +all: $(PROG) + +clean: + rm -f *.o $(PROG) + +# Rules +$(PROG): main.o util.o none.o sha2.o scrypt.o + $(GCC) $(CFLAGS) -o $@ $+ $(LDFLAGS) + +%.o: %.c makefile $(wildcard *.h) + $(GCC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< diff --git a/none.c b/none.c new file mode 100644 index 0000000..48df738 --- /dev/null +++ b/none.c @@ -0,0 +1,17 @@ +#include + +#include "none.h" + +void none_test(void) +{ +} + +void none_enc(void *in, void *out, int len) +{ + memcpy(out, in, len); +} + +void none_dec(void *in, void *out, int len) +{ + memcpy(out, in, len); +} diff --git a/none.h b/none.h new file mode 100644 index 0000000..210f111 --- /dev/null +++ b/none.h @@ -0,0 +1,4 @@ +/* none functions */ +void none_test(void); +void none_enc(void *in, void *out, int len); +void none_dec(void *in, void *out, int len); diff --git a/scrypt.c b/scrypt.c new file mode 100644 index 0000000..a85eccd --- /dev/null +++ b/scrypt.c @@ -0,0 +1,245 @@ +#include +#include +#include + +#include "util.h" +#include "sha2.h" +#include "scrypt.h" + +/** + * Name RFC Description + * pass P Passphrase, an octet string. + * salt S Salt, an octet string. + * cost N CPU/Memory cost parameter + * bs r Block size parameter. + * par p Parallelization parameter + * len? dkLen Intended output length + * in B Input data + * out B' Output data + */ + +/* Types */ +typedef void hash_t(uint8_t *out, const uint8_t *in, int len); + +/* Helpers */ +#if 0 +static int mod(uint8_t out[64], uint8_t in[64]) +{ +} + +static void copy(uint8_t out[64], uint8_t in[64]) +{ +} + +static void xor(uint8_t out[64], uint8_t a[64], uint8_t b[64]) +{ +} +#endif + +/* HMAC */ +static void hmac_gen(hash_t hash, + uint8_t *out, int nout, + const uint8_t *key, int nkey, + const uint8_t *msg, int nmsg) +{ + uint8_t *fix = alloc0(nout); + uint8_t *ipad = alloc0(nout+nmsg); + uint8_t *opad = alloc0(nout+nout); + + /* Fixup key */ + if (nkey > nout) + hash(fix, key, nkey); + else + memcpy(fix, key, nkey); + + /* Create pad strings */ + for (int i = 0; i < nout; i++) { + opad[i] = 0x5c ^ fix[i]; + ipad[i] = 0x36 ^ fix[i]; + } + + /* Run hashes - hash(o+hash(i+msg)) */ + memcpy(ipad+nout, msg, nmsg); + hash(opad+nout, ipad, nout+nmsg); + hash(out, opad, nout+nout); + + /* Cleanup */ + free(fix); + free(opad); + free(ipad); +} + +/* PBKDF2 */ +static void pbkdf2_gen(uint8_t *out, int nout, + const uint8_t *pass, int npass, + const uint8_t *salt, int nsalt, + int iter) +{ + int nbuf = nsalt + 4; + uint8_t *buf = alloc0(nbuf); + memcpy(buf, salt, nsalt); + + const int nptr = 256/8; + + for (int i = 0; i < nout/nptr; i++) { + uint8_t *ptr = &out[i*nptr]; + + buf[nsalt+0] = ((i+1) & 0xFF000000) >> 030; + buf[nsalt+1] = ((i+1) & 0x00FF0000) >> 020; + buf[nsalt+2] = ((i+1) & 0x0000FF00) >> 010; + buf[nsalt+3] = ((i+1) & 0x000000FF) >> 000; + + hmac_gen(sha256_hash, ptr, nptr, pass, npass, buf, nbuf); + for (int j = 1; j < iter; j++) + hmac_gen(sha256_hash, ptr, nptr, pass, npass, ptr, nptr); + } + + free(buf); +} + +static void pbkdf2_gen_str(uint8_t *out, int nout, + const char *pass, const char *salt, int iter) +{ + pbkdf2_gen(out, nout, + (const uint8_t *)pass, strlen(pass), + (const uint8_t *)salt, strlen(salt), iter); +} + +/* Salsa20/8 */ +static void salsa(uint8_t out[64], uint8_t in[64]) +{ +} + +/* scrypt */ +#if 0 +static void block_mix(uint8_t *out[64], uint8_t *in[64], int bs) +{ + // xor each block with the last block + // alternat first/second half for result + + uint8_t tmp[64] + for (int i = 0; i < 2*r; i++) { + int o = bs*(i%2) + (i/2); + xor(tmp, in[2*r - 1], in[i]); + salsa(out[o], tmp); + } +} + +static void ro_mix(uint8_t *out[128], uint8_t *in[128], int cost, int bs) +{ + // generate vector of size cost + // randomly collapse vector as output + + uint8_t *state[64]; + uint8_t *mixed[64]; + uint8_t *tmp[64]; + + copy(state, in); + + for (i = 0; i < cost; i++) { + copy(mixed[i], state); + block_mix(state, state); + } + + for (i = 0; i < cost; i++) { + int j = mod(state, cost); + xor(tmp, state, mixed[j]); + block_mix(state, tmp); + } + + copy(out, state); +} + +static void scrypt_run(uint8_t out[64], + char *pass, char *salt, + int cost, int bs, int par, int len) +{ + // hash pass/salt into large buffer + // mix each buffer (in parallel) + // combine bubers into output + + sha256_hmac(buf, pass, salt, 1, par * 128 * bs); + + for (i = 0; i < par; i++) + buf[i] = ro_mix(buf[i], cost, bs); + + sha256_hmac(out, pass, buf, 1, len); +} +#endif + +/* Entry point */ +void scrypt_hash(uint8_t *in, uint8_t *sum) +{ + *sum = 0; +} + +/* Tests */ +#if 0 +static void test_script(void) +{ + /* Parameters */ + const int cost = 1024; + const int bs = 1; + const int par = 1; + const int len = 32; + + /* Input data */ + const char *pass = "hello"; + const char *salt = "world"; + + /* Output data */ + static uint8_t out[32]; + + /* Run the hash */ + scrypt_hash(out, pass, salt, par, bs, len); + + /* Print output */ +} +#endif + +static void test_keygen(void) +{ + const uint8_t truth0[] = { + 0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f, + 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05, + 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65, + 0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc, + 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45, + 0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31, + 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5, + 0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83, + }; + + const uint8_t truth1[] = { + 0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21, + 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9, + 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14, + 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56, + 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54, + 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17, + 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78, + 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d, + }; + + uint8_t out0[64] = {}; + uint8_t out1[64] = {}; + + // output password salt iters + pbkdf2_gen_str(out0, 64, "passwd", "salt", 1); + //pbkdf2_gen_str(out1, 64, "Password", "NaCl", 80000); + + hexdump("\nTest #1", NULL, truth0, 64); + hexdump("", NULL, out0, 64); + + hexdump("\nTest #2", NULL, truth1, 64); + hexdump("", NULL, out1, 64); + + (void)salsa; + (void)pbkdf2_gen; + (void)hmac_gen; +} + +void scrypt_test(void) +{ + test_keygen(); +} diff --git a/scrypt.h b/scrypt.h new file mode 100644 index 0000000..1ee717b --- /dev/null +++ b/scrypt.h @@ -0,0 +1,3 @@ +/* scrypt functions */ +void scrypt_test(); +void scrypt_hash(uint8_t *in, uint8_t *sum); diff --git a/sha2.c b/sha2.c new file mode 100644 index 0000000..b686d3e --- /dev/null +++ b/sha2.c @@ -0,0 +1,49 @@ +#include + +#include "util.h" +#include "sha2.h" + +/* Hashes: + * SHA-224 + * SHA-256 + * SHA-384 + * SHA-512 + * SHA-512/224 + * SHA-512/256 + */ + +/* From Fitz */ +typedef struct { + unsigned int state[8]; + unsigned int count[2]; + union { + unsigned char u8[64]; + unsigned int u32[16]; + } buffer; +} fz_sha256; + +void fz_sha256_init(fz_sha256 *state); +void fz_sha256_update(fz_sha256 *state, const unsigned char *input, unsigned int inlen); +void fz_sha256_final(fz_sha256 *state, unsigned char digest[32]); + +/* SHA-256 */ +void sha256_hash(uint8_t out[32], const uint8_t *data, int len) +{ + fz_sha256 state = {}; + + fz_sha256_init(&state); + fz_sha256_update(&state, data, len); + fz_sha256_final(&state, out); +} + +/* Test */ +void sha256_test(void) +{ + uint8_t in[] = "hello"; + uint8_t out[32] = {}; + + sha256_hash(out, in, sizeof(in)-1); + + hexdump("Input:", "\t%04x: ", in, sizeof(in)-1); + hexdump("Output:", "\t%04x: ", out, sizeof(out)); +} diff --git a/sha2.h b/sha2.h new file mode 100644 index 0000000..476c6a0 --- /dev/null +++ b/sha2.h @@ -0,0 +1,3 @@ +/* SHA-2 functions */ +void sha256_test(void); +void sha256_hash(uint8_t out[32], const uint8_t *data, int len); diff --git a/util.c b/util.c new file mode 100644 index 0000000..dd047b8 --- /dev/null +++ b/util.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +/* Log levels */ +#define LOG_DEFAULT LOG_INFO + +typedef enum { + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, +} log_t; + +/* Globals */ +int loglevel; + +/* Helper functions */ +static void message(int level, const char *prefix, const char *fmt, va_list ap) +{ + if (level >= LOG_DEFAULT-loglevel) { + fprintf(stderr, "%s: ", prefix); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } +} + +/* Mesage functions */ +void debug(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + message(LOG_DEBUG, "debug", fmt, ap); + va_end(ap); +} + +void info(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + message(LOG_INFO, "info", fmt, ap); + va_end(ap); +} + +void warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + message(LOG_WARN, "warning", fmt, ap); + va_end(ap); +} + +void error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + message(LOG_ERROR, "error", fmt, ap); + va_end(ap); + exit(1); +} + +/* Hex dump */ +void hexdump(const char *label, const char *prefix, + const uint8_t *data, int len, ...) +{ + va_list ap; + va_start(ap, len); + + if (!label) label = ""; + if (!prefix) prefix = "%04x: "; + + vprintf(label, ap); + for (int i = 0; i < len; i++) { + if ((i % 16) == 0) { + printf("\n"); + printf(prefix, i); + } else if ((i % 8) == 0) { + printf(" "); + } else if ((i % 2) == 0) { + printf(" "); + } + printf("%02hhx", data[i]); + } + printf("\n"); + + va_end(ap); +} + + +/* Misc */ +void *alloc0(int size) +{ + void *out = calloc(1, size); + if (!out) + error("Alloc failed"); + return out; +} diff --git a/util.h b/util.h new file mode 100644 index 0000000..4ab68e3 --- /dev/null +++ b/util.h @@ -0,0 +1,17 @@ +/* Macros */ +#define N_ELEM(x) (sizeof(x)/sizeof(*(x))) + +/* Globals */ +extern int loglevel; + +/* Debug functions */ +void info(const char *fmt, ...); +void debug(const char *fmt, ...); +void warn(const char *fmt, ...); +void error(const char *fmt, ...); + +/* Output functions */ +void hexdump(const char *fmt, const char *prefix, const uint8_t *data, ...); + +/* Misc */ +void *alloc0(int size); -- 2.43.2