--- /dev/null
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#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;
+};
+
--- /dev/null
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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();
+}