voxabdo

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

voxabdo.c
1#include <getopt.h>
2#include <stdarg.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <string.h>
6#include <time.h>
7
8/* Brad Contes implementation of sha256 */
9#include "sha256.h"
10
11#define SEED_LENGTH     8
12#define RAND_K1         1103515245
13#define RAND_K2         12345
14/* just a simpler way of writing putc(c, stdout) */
15#define PUT(x)          (putc((x), stdout))
16
17void die(const char*, ...); /* print message and exit */
18int idx(const BYTE[], const BYTE); /* first index of byte in byte array */
19int uniq(const BYTE*); /* checks if bytes are unique in byte array */
20int msrand(int n); /* implementation of rand with support for multiple seeds */
21void seed_init(const BYTE*); /* initializes 8 seeds using a sha256 hash */
22void seed_password(const char*); /* converts a password into seeds */
23void generate_key(BYTE**); /* generates a 16 byte random key (based on seeds) */
24void encode(BYTE*[]); /* encodes input */
25void decode(BYTE*[]); /* decodes input */
26
27static const char *usage = "usage: voxabdo [-dh] [-p password] [-x key -y key]";
28static int seed[SEED_LENGTH] = { 0 };
29
30void
31die(const char *msg, ...)
32{
33    va_list arguments;
34
35    va_start(arguments, msg);
36    if (msg)
37        vfprintf(stderr, msg, arguments);
38    va_end(arguments);
39
40    exit(1);
41}
42
43int
44idx(const BYTE key[], const BYTE c)
45{
46    int i;
47
48    for (i = 0; i < 16; i++) {
49        if (key[i] == c)
50            return i;
51    }
52
53    die("index out of bounds\n");
54    return -1; /* will never be reached */
55}
56
57int
58uniq(const BYTE *str)
59{
60    int i, j;
61
62    for (i = 0; i < 16; i++) {
63        for (j = 0; j < 16; j++) {
64            if (i == j)
65                continue;
66            if (str[i] == str[j])
67                return 0;
68        }
69    }
70    return 1;
71}
72
73int
74msrand(int n)
75{
76    unsigned int next = seed[n];
77    int result;
78
79    next *= RAND_K1;
80    next += RAND_K2;
81    result = (unsigned int) (next / 65536) % 2048;
82
83    next *= RAND_K1;
84    next += RAND_K2;
85    result <<= 10;
86    result ^= (unsigned int) (next / 65536) % 1024;
87
88    next *= RAND_K1;
89    next += RAND_K2;
90    result <<= 10;
91    result ^= (unsigned int) (next / 65536) % 1024;
92
93    seed[n] = next;
94    return result;
95}
96
97void
98seed_init(const BYTE *hash)
99{
100    int i;
101
102    for (i = (SHA256_BLOCK_SIZE - 1) * 8; i >= 0; i--)
103        seed[i / 32] |= (1U & (hash[i / 8] >> (i % 8))) << (i % 32);
104}
105
106void
107seed_password(const char *password)
108{
109    BYTE buffer[SHA256_BLOCK_SIZE];
110    SHA256_CTX ctx;
111
112    sha256_init(&ctx);
113    sha256_update(&ctx, (BYTE *)password, strlen(password));
114    sha256_final(&ctx, buffer);
115    seed_init(buffer);
116}
117
118void
119generate_key(BYTE **key)
120{
121    int i, j, s;
122    BYTE c;
123
124    (*key) = (BYTE*)malloc(16 * sizeof(char));
125
126    for (i = 0, s = 0; i < 16; i++) {
127        (*key)[i] = (c = (BYTE)(msrand(s++) % 256));
128
129        /* circulate seed counter */
130        if (s == SEED_LENGTH)
131            s = 0;
132
133        /* if first byte, don't check uniqueness */
134        if (i == 0)
135            continue;
136
137        /* check if byte allready exist, and if so redo generation (i--) */
138        for (j = 0; j < i; j++) {
139            if ((*key)[j] == c) {
140                i--;
141                continue;
142            }
143        }
144    }
145}
146
147void
148encode(BYTE *key[])
149{
150    int i;
151    BYTE c, x, y;
152    BYTE *ikey[2] = {NULL};
153
154    /* randomize seed */
155    srand(time(NULL));
156    for (i = 0; i < SEED_LENGTH; i++)
157        seed[i] = rand();
158
159    /* create inner keys */
160    generate_key(&(ikey[0]));
161    generate_key(&(ikey[1]));
162
163    /* output the inner keys encoded by the outer keys */
164    for (i = 0; i < 32; i++) {
165        c = ikey[(i >= 16)][i % 16];
166        PUT(key[0][c / 16]);
167        PUT(key[1][c % 16]);
168    }
169
170    /* output input encoded first by the inner keys, then by the outer keys */
171    for (;;) {
172        c = getc(stdin);
173        if (feof(stdin))
174            break;
175        x = ikey[0][c / 16];
176        PUT(key[0][x / 16]);
177        PUT(key[1][x % 16]);
178
179        y = ikey[1][c % 16];
180        PUT(key[0][y / 16]);
181        PUT(key[1][y % 16]);
182    }
183    free(ikey[0]);
184    free(ikey[1]);
185}
186
187void
188decode(BYTE *key[])
189{
190    int i;
191    BYTE c, x, y;
192    BYTE ikey[2][16] = {0};
193
194    for (i = 0;; i++) {
195        c = getc(stdin);
196        if (feof(stdin))
197            break;
198        if (i < 64) { /* extract inner keys */
199            ikey[i >= 32][(i / 2) % 16] +=
200                (i % 2 == 0)
201                ? idx(key[0], c) * 16
202                : idx(key[1], c);
203            continue;
204        }
205        if (i == 64 && (!uniq(ikey[0]) || !uniq(ikey[1])))
206            die("keys are not unique\n");
207        switch (i % 4) { /* extract all parts of input and decode it */
208        case 0:
209            x = idx(key[0], c) * 16;
210            break;
211        case 1:
212            x += idx(key[1], c);
213            break;
214        case 2:
215            y = idx(key[0], c) * 16;
216            break;
217        case 3:
218            y += idx(key[1], c);
219            PUT(idx(ikey[0], x) * 16 + idx(ikey[1], y));
220            break;
221        }
222    }
223}
224
225int
226main(int argc, char *argv[])
227{
228    char c;
229    char *password = NULL;
230    BYTE *key[2] = {NULL};
231    int doencode = 1;
232
233    while ((c = getopt(argc, argv, "dhp:x:y:")) != -1) {
234        switch (c) {
235        case 'd':
236            doencode = 0;
237            break;
238        case 'p':
239            password = (char*)malloc((strlen(optarg) + 1) * sizeof(char));
240            memmove(password, optarg, strlen(optarg));
241            break;
242        case 'x':
243        case 'y':
244            if (strlen(optarg) != 16)
245                die("The '%c' key must contain exactly 16 bytes\n", c);
246            key[c == 'y'] = (BYTE*)malloc(16 * sizeof(char));
247            memmove(key[c == 'y'], optarg, 16);
248            if (!uniq(key[c == 'y']))
249                die("All bytes in the '%c' key must be unique\n", c);
250            break;
251        case 'h':
252            fprintf(stderr, "%s\n", usage);
253            fprintf(stderr, " -d           decode input\n");
254            fprintf(stderr, " -h           print this help text and exit\n");
255            fprintf(stderr, " -p PASSWORD  specify a PASSWORD\n");
256            fprintf(stderr, " -x KEY       specify 16 unique bytes as key\n");
257            fprintf(stderr, " -y KEY       specify 16 unique bytes as key\n");
258            exit(0);
259            break;
260        default:
261            fprintf(stderr, "%s\n", usage);
262            exit(1);
263            break;
264        }
265    }
266
267    /* validate input */
268    if (password && (key[0] || key[1]))
269        die("You cannot specify both password and keys\n");
270    if (!password && !(key[0] || key[1]))
271        die("You must specify either a password or keys\n");
272    if (!password && (!key[0] || !key[1]))
273        die("You must specify both 'x' and 'y' keys\n");
274
275    if (password) {
276        seed_password(password);
277        generate_key(&(key[0]));
278        generate_key(&(key[1]));
279        free(password);
280    }
281
282    if (doencode)
283        encode(key);
284    else
285        decode(key);
286
287    free(key[0]);
288    free(key[1]);
289    return 0;
290}