voxabdo

Implementation of the voxabdo cipher in c
git clone https://noxz.tech/git/voxabdo.git
Log | Files

commit: 2344ca3f8f43ee8154fada4c0a3d6d399fff0962
parent: 
author: Chris Noxz <chris@noxz.tech>
date:   Sat, 29 Feb 2020 11:37:43 +0100
initial commit
A.gitignore2+
AMakefile37+++
Aconfig.mk8+
Asha256.c159+++++++++++
Asha256.h34+++
Avoxabdo.c290++++++++++++++++++++
6 files changed, 530 insertions(+)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+voxabdo
+*.o
diff --git a/Makefile b/Makefile
@@ -0,0 +1,37 @@
+.POSIX:
+
+include config.mk
+
+SRC = voxabdo.c sha256.c
+OBJ = $(SRC:.c=.o)
+
+all: options voxabdo
+
+options:
+	@echo voxabdo build options:
+	@echo "VERSION = $(VERSION)"
+	@echo "PREFIX  = $(PREFIX)"
+	@echo "CFLAGS  = $(STCFLAGS)"
+	@echo "CC      = $(CC)"
+
+.c.o:
+	$(CC) $(STCFLAGS) -c $<
+
+$(OBJ): config.mk
+
+voxabdo: $(OBJ)
+	$(CC) -o $@ $(OBJ) $(STCFLAGS)
+
+clean:
+	rm -f voxabdo $(OBJ)
+
+install: voxabdo
+	@echo installing executable to ${PREFIX}/bin
+	mkdir -p $(PREFIX)/bin
+	cp -f voxabdo $(PREFIX)/bin
+	chmod 755 $(PREFIX)/bin/voxabdo
+
+uninstall:
+	rm -f $(PREFIX)/bin/voxabdo
+
+.PHONY: all options clean install uninstall
diff --git a/config.mk b/config.mk
@@ -0,0 +1,8 @@
+VERSION = 0.0.1
+
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+
+CFLAGS = -Wall -pedantic -std=c99
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+STCFLAGS = $(CPPFLAGS) $(CFLAGS)
diff --git a/sha256.c b/sha256.c
@@ -0,0 +1,159 @@
+/*********************************************************************
+* Filename:   sha256.c
+* Author:     Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details:    Implementation of the SHA-256 hashing algorithm.
+              SHA-256 is one of the three algorithms in the SHA2
+              specification. The others, SHA-384 and SHA-512, are not
+              offered in this implementation.
+              Algorithm specification can be found here:
+* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
+              This implementation uses little endian byte order.
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include <stdlib.h>
+#include <memory.h>
+#include "sha256.h"
+
+/****************************** MACROS ******************************/
+#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
+#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
+
+#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
+#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
+#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
+#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
+#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
+#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
+
+/**************************** VARIABLES *****************************/
+static const WORD k[64] = {
+    0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
+    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
+    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
+    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
+    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
+    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
+    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
+{
+    WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
+
+    for (i = 0, j = 0; i < 16; ++i, j += 4)
+        m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
+    for ( ; i < 64; ++i)
+        m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
+
+    a = ctx->state[0];
+    b = ctx->state[1];
+    c = ctx->state[2];
+    d = ctx->state[3];
+    e = ctx->state[4];
+    f = ctx->state[5];
+    g = ctx->state[6];
+    h = ctx->state[7];
+
+    for (i = 0; i < 64; ++i) {
+        t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
+        t2 = EP0(a) + MAJ(a,b,c);
+        h = g;
+        g = f;
+        f = e;
+        e = d + t1;
+        d = c;
+        c = b;
+        b = a;
+        a = t1 + t2;
+    }
+
+    ctx->state[0] += a;
+    ctx->state[1] += b;
+    ctx->state[2] += c;
+    ctx->state[3] += d;
+    ctx->state[4] += e;
+    ctx->state[5] += f;
+    ctx->state[6] += g;
+    ctx->state[7] += h;
+}
+
+void sha256_init(SHA256_CTX *ctx)
+{
+    ctx->datalen = 0;
+    ctx->bitlen = 0;
+    ctx->state[0] = 0x6a09e667;
+    ctx->state[1] = 0xbb67ae85;
+    ctx->state[2] = 0x3c6ef372;
+    ctx->state[3] = 0xa54ff53a;
+    ctx->state[4] = 0x510e527f;
+    ctx->state[5] = 0x9b05688c;
+    ctx->state[6] = 0x1f83d9ab;
+    ctx->state[7] = 0x5be0cd19;
+}
+
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
+{
+    WORD i;
+
+    for (i = 0; i < len; ++i) {
+        ctx->data[ctx->datalen] = data[i];
+        ctx->datalen++;
+        if (ctx->datalen == 64) {
+            sha256_transform(ctx, ctx->data);
+            ctx->bitlen += 512;
+            ctx->datalen = 0;
+        }
+    }
+}
+
+void sha256_final(SHA256_CTX *ctx, BYTE hash[])
+{
+    WORD i;
+
+    i = ctx->datalen;
+
+    // Pad whatever data is left in the buffer.
+    if (ctx->datalen < 56) {
+        ctx->data[i++] = 0x80;
+        while (i < 56)
+            ctx->data[i++] = 0x00;
+    }
+    else {
+        ctx->data[i++] = 0x80;
+        while (i < 64)
+            ctx->data[i++] = 0x00;
+        sha256_transform(ctx, ctx->data);
+        memset(ctx->data, 0, 56);
+    }
+
+    // Append to the padding the total message's length in bits and transform.
+    ctx->bitlen += ctx->datalen * 8;
+    ctx->data[63] = ctx->bitlen;
+    ctx->data[62] = ctx->bitlen >> 8;
+    ctx->data[61] = ctx->bitlen >> 16;
+    ctx->data[60] = ctx->bitlen >> 24;
+    ctx->data[59] = ctx->bitlen >> 32;
+    ctx->data[58] = ctx->bitlen >> 40;
+    ctx->data[57] = ctx->bitlen >> 48;
+    ctx->data[56] = ctx->bitlen >> 56;
+    sha256_transform(ctx, ctx->data);
+
+    // Since this implementation uses little endian byte ordering and SHA uses 
+    // big endian,
+    // reverse all the bytes when copying the final state to the output hash.
+    for (i = 0; i < 4; ++i) {
+        hash[i]      = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 4]  = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 8]  = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
+        hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
+    }
+}
diff --git a/sha256.h b/sha256.h
@@ -0,0 +1,34 @@
+/*********************************************************************
+* Filename:   sha256.h
+* Author:     Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details:    Defines the API for the corresponding SHA1 implementation.
+*********************************************************************/
+
+#ifndef SHA256_H
+#define SHA256_H
+
+/*************************** HEADER FILES ***************************/
+#include <stddef.h>
+
+/****************************** MACROS ******************************/
+#define SHA256_BLOCK_SIZE 32            // SHA256 outputs a 32 byte digest
+
+/**************************** DATA TYPES ****************************/
+typedef unsigned char BYTE;             // 8-bit byte
+typedef unsigned int  WORD;             // 32-bit word, change to "long" for 16-bit machines
+
+typedef struct {
+    BYTE data[64];
+    WORD datalen;
+    unsigned long long bitlen;
+    WORD state[8];
+} SHA256_CTX;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+void sha256_init(SHA256_CTX *ctx);
+void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
+void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
+
+#endif   // SHA256_H
diff --git a/voxabdo.c b/voxabdo.c
@@ -0,0 +1,290 @@
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+/* Brad Contes implementation of sha256 */
+#include "sha256.h"
+
+#define SEED_LENGTH     8
+#define RAND_K1         1103515245
+#define RAND_K2         12345
+/* just a simpler way of writing putc(c, stdout) */
+#define PUT(x)          (putc((x), stdout))
+
+void die(const char*, ...); /* print message and exit */
+int idx(const BYTE[], const BYTE); /* first index of byte in byte array */
+int uniq(const BYTE*); /* checks if bytes are unique in byte array */
+int msrand(int n); /* implementation of rand with support for multiple seeds */
+void seed_init(const BYTE*); /* initializes 8 seeds using a sha256 hash */
+void seed_password(const char*); /* converts a password into seeds */
+void generate_key(BYTE**); /* generates a 16 byte random key (based on seeds) */
+void encode(BYTE*[]); /* encodes input */
+void decode(BYTE*[]); /* decodes input */
+
+static const char *usage = "usage: voxabdo [-dh] [-p password] [-x key -y key]";
+static int seed[SEED_LENGTH] = { 0 };
+
+void
+die(const char *msg, ...)
+{
+    va_list arguments;
+
+    va_start(arguments, msg);
+    if (msg)
+        vfprintf(stderr, msg, arguments);
+    va_end(arguments);
+
+    exit(1);
+}
+
+int
+idx(const BYTE key[], const BYTE c)
+{
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        if (key[i] == c)
+            return i;
+    }
+
+    die("index out of bounds\n");
+    return -1; /* will never be reached */
+}
+
+int
+uniq(const BYTE *str)
+{
+    int i, j;
+
+    for (i = 0; i < 16; i++) {
+        for (j = 0; j < 16; j++) {
+            if (i == j)
+                continue;
+            if (str[i] == str[j])
+                return 0;
+        }
+    }
+    return 1;
+}
+
+int
+msrand(int n)
+{
+    unsigned int next = seed[n];
+    int result;
+
+    next *= RAND_K1;
+    next += RAND_K2;
+    result = (unsigned int) (next / 65536) % 2048;
+
+    next *= RAND_K1;
+    next += RAND_K2;
+    result <<= 10;
+    result ^= (unsigned int) (next / 65536) % 1024;
+
+    next *= RAND_K1;
+    next += RAND_K2;
+    result <<= 10;
+    result ^= (unsigned int) (next / 65536) % 1024;
+
+    seed[n] = next;
+    return result;
+}
+
+void
+seed_init(const BYTE *hash)
+{
+    int i;
+
+    for (i = (SHA256_BLOCK_SIZE - 1) * 8; i >= 0; i--)
+        seed[i / 32] |= (1U & (hash[i / 8] >> (i % 8))) << (i % 32);
+}
+
+void
+seed_password(const char *password)
+{
+    BYTE buffer[SHA256_BLOCK_SIZE];
+    SHA256_CTX ctx;
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, (BYTE *)password, strlen(password));
+    sha256_final(&ctx, buffer);
+    seed_init(buffer);
+}
+
+void
+generate_key(BYTE **key)
+{
+    int i, j, s;
+    BYTE c;
+
+    (*key) = (BYTE*)malloc(16 * sizeof(char));
+
+    for (i = 0, s = 0; i < 16; i++) {
+        (*key)[i] = (c = (BYTE)(msrand(s++) % 256));
+
+        /* circulate seed counter */
+        if (s == SEED_LENGTH)
+            s = 0;
+
+        /* if first byte, don't check uniqueness */
+        if (i == 0)
+            continue;
+
+        /* check if byte allready exist, and if so redo generation (i--) */
+        for (j = 0; j < i; j++) {
+            if ((*key)[j] == c) {
+                i--;
+                continue;
+            }
+        }
+    }
+}
+
+void
+encode(BYTE *key[])
+{
+    int i;
+    BYTE c, x, y;
+    BYTE *ikey[2] = {NULL};
+
+    /* randomize seed */
+    srand(time(NULL));
+    for (i = 0; i < SEED_LENGTH; i++)
+        seed[i] = rand();
+
+    /* create inner keys */
+    generate_key(&(ikey[0]));
+    generate_key(&(ikey[1]));
+
+    /* output the inner keys encoded by the outer keys */
+    for (i = 0; i < 32; i++) {
+        c = ikey[(i >= 16)][i % 16];
+        PUT(key[0][c / 16]);
+        PUT(key[1][c % 16]);
+    }
+
+    /* output input encoded first by the inner keys, then by the outer keys */
+    for (;;) {
+        c = getc(stdin);
+        if (feof(stdin))
+            break;
+        x = ikey[0][c / 16];
+        PUT(key[0][x / 16]);
+        PUT(key[1][x % 16]);
+
+        y = ikey[1][c % 16];
+        PUT(key[0][y / 16]);
+        PUT(key[1][y % 16]);
+    }
+    free(ikey[0]);
+    free(ikey[1]);
+}
+
+void
+decode(BYTE *key[])
+{
+    int i;
+    BYTE c, x, y;
+    BYTE ikey[2][16] = {0};
+
+    for (i = 0;; i++) {
+        c = getc(stdin);
+        if (feof(stdin))
+            break;
+        if (i < 64) { /* extract inner keys */
+            ikey[i >= 32][(i / 2) % 16] +=
+                (i % 2 == 0)
+                ? idx(key[0], c) * 16
+                : idx(key[1], c);
+            continue;
+        }
+        if (i == 64 && (!uniq(ikey[0]) || !uniq(ikey[1])))
+            die("keys are not unique\n");
+        switch (i % 4) { /* extract all parts of input and decode it */
+        case 0:
+            x = idx(key[0], c) * 16;
+            break;
+        case 1:
+            x += idx(key[1], c);
+            break;
+        case 2:
+            y = idx(key[0], c) * 16;
+            break;
+        case 3:
+            y += idx(key[1], c);
+            PUT(idx(ikey[0], x) * 16 + idx(ikey[1], y));
+            break;
+        }
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+    char c;
+    char *password = NULL;
+    BYTE *key[2] = {NULL};
+    int doencode = 1;
+
+    while ((c = getopt(argc, argv, "dhp:x:y:")) != -1) {
+        switch (c) {
+        case 'd':
+            doencode = 0;
+            break;
+        case 'p':
+            password = (char*)malloc((strlen(optarg) + 1) * sizeof(char));
+            memmove(password, optarg, strlen(optarg));
+            break;
+        case 'x':
+        case 'y':
+            if (strlen(optarg) != 16)
+                die("The '%c' key must contain exactly 16 bytes\n", c);
+            key[c == 'y'] = (BYTE*)malloc(16 * sizeof(char));
+            memmove(key[c == 'y'], optarg, 16);
+            if (!uniq(key[c == 'y']))
+                die("All bytes in the '%c' key must be unique\n", c);
+            break;
+        case 'h':
+            fprintf(stderr, "%s\n", usage);
+            fprintf(stderr, " -d           decode input\n");
+            fprintf(stderr, " -h           print this help text and exit\n");
+            fprintf(stderr, " -p PASSWORD  specify a PASSWORD\n");
+            fprintf(stderr, " -x KEY       specify 16 unique bytes as key\n");
+            fprintf(stderr, " -y KEY       specify 16 unique bytes as key\n");
+            exit(0);
+            break;
+        default:
+            fprintf(stderr, "%s\n", usage);
+            exit(1);
+            break;
+        }
+    }
+
+    /* validate input */
+    if (password && (key[0] || key[1]))
+        die("You cannot specify both password and keys\n");
+    if (!password && !(key[0] || key[1]))
+        die("You must specify either a password or keys\n");
+    if (!password && (!key[0] || !key[1]))
+        die("You must specify both 'x' and 'y' keys\n");
+
+    if (password) {
+        seed_password(password);
+        generate_key(&(key[0]));
+        generate_key(&(key[1]));
+        free(password);
+    }
+
+    if (doencode)
+        encode(key);
+    else
+        decode(key);
+
+    free(key[0]);
+    free(key[1]);
+    return 0;
+}