commit 9d53f2f47cf6adbd1905ae516a12f8bf5021cf94
Author: Dominik Schmidt <dominik@schm1dt.ch>
Date: Sun, 23 Dec 2018 12:14:37 +0100
Initial commit
Diffstat:
Makefile | | | 7 | +++++++ |
nettle.c | | | 447 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 454 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,7 @@
+
+
+nettle: nettle.o
+ gcc -g -o $@ $^ `pkg-config --libs nettle`
+
+nettle.o: nettle.c
+ gcc -g -c -o $@ $^ `pkg-config --cflags nettle`
diff --git a/nettle.c b/nettle.c
@@ -0,0 +1,447 @@
+#include <nettle/nettle-meta.h>
+#include <nettle/cbc.h>
+#include <nettle/aes.h>
+#include <nettle/ctr.h>
+#include <nettle/cfb.h>
+#include <nettle/blowfish.h>
+#include <nettle/arcfour.h>
+#include <nettle/macros.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+enum MODE{
+ ECB,
+ CBC,
+ CTR,
+ CFB,
+ INVALID
+};
+
+enum DIRECTION{
+ ENCRYPT,
+ DECRYPT
+};
+
+typedef struct{
+ size_t len;
+ char *str;
+} String;
+
+struct EncStage{
+ enum MODE mode;
+ enum DIRECTION dir;
+ const struct nettle_cipher *cipher;
+
+ size_t len;
+ uint8_t* src;
+ uint8_t* dst;
+ String key;
+ String iv;
+
+};
+
+String readFile(FILE *f, size_t maxSize){
+ size_t ret=0;
+ size_t alloc=1024;
+ size_t size=0;
+ uint8_t *buf=NULL;
+ while(1){
+ buf=realloc(buf, alloc);
+ if(buf==NULL){
+ fprintf(stderr, "Allocation failure\n");
+ }
+ ret=fread(buf+size, 1, alloc-size, f);
+ size+=ret;
+ if(ret<alloc-size){
+ break;
+ }
+ }
+ buf[size]='\0';
+ String s={.len=size, .str=buf};
+ return s;
+}
+
+String argString(char *arg){
+ if(arg[0]=='@'){
+ if(arg[1]=='@'){
+ return (String){.str=&arg[2],.len=strlen(&arg[2])};
+ }
+ else{
+ FILE *f=fopen(&arg[1], "r");
+ if(f==NULL){
+ perror("Could not open file");
+ return (String){.str=NULL,.len=0};
+ }
+ String ret=readFile(f, SIZE_MAX);
+ if(ret.str==NULL){
+ fprintf(stderr, "Couldnt read file\n");
+ }
+ return ret;
+
+ }
+ }
+ else{
+ return (String){.str=arg, .len=strlen(arg)};
+ }
+}
+
+const static size_t tea_block_size=4*2;
+const static size_t tea_key_size=4*4;
+const static size_t tea_context_size=tea_key_size;
+
+void tea_encrypt_block (uint32_t v[2], const uint32_t k[4]) {
+ uint32_t v0=v[0], v1=v[1], sum=0, i; /* set up */
+ uint32_t delta=0x9E3779B9; /* a key schedule constant */
+ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
+ for (i=0; i<32; i++) { /* basic cycle start */
+ sum += delta;
+ v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
+ v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
+ } /* end cycle */
+ v[0]=v0; v[1]=v1;
+}
+
+void tea_decrypt_block (uint32_t v[2], const uint32_t k[4]) {
+ uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up; sum is 32*delta */
+ uint32_t delta=0x9E3779B9; /* a key schedule constant */
+ uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
+ for (i=0; i<32; i++) { /* basic cycle start */
+ v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
+ v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
+ sum -= delta;
+ } /* end cycle */
+ v[0]=v0; v[1]=v1;
+}
+
+void tea_encrypt(const void *ctx, size_t len, uint8_t *dst, const uint8_t *src){
+ memcpy(dst, src, len);
+ uint8_t *cur;
+ //assert(!(len%tea_block_size));
+ for(cur=dst; cur<dst+len; cur+=tea_block_size){
+ tea_encrypt_block((uint32_t*)cur, (uint32_t*)ctx);
+ }
+}
+
+void tea_decrypt(const void *ctx, size_t len, uint8_t *dst, const uint8_t *src){
+ memcpy(dst, src, len);
+ uint8_t *cur;
+ //assert(!(len%tea_block_size));
+ for(cur=dst; cur<dst+len; cur+=tea_block_size){
+ tea_decrypt_block((uint32_t*)cur, (uint32_t*)ctx);
+ }
+}
+
+void tea_set_key(void *ctx, const uint8_t *key){
+ memcpy(ctx, key, tea_key_size);
+}
+
+const struct nettle_cipher nettle_tea={
+ .name="tea128",
+ .context_size=tea_context_size,
+ .block_size=tea_block_size,
+ .key_size=tea_key_size,
+ .set_encrypt_key=&tea_set_key,
+ .set_decrypt_key=&tea_set_key,
+ .encrypt=&tea_encrypt,
+ .decrypt=&tea_decrypt
+};
+
+const struct nettle_cipher nettle_blowfish128={
+ .name="blowfish128",
+ .context_size=sizeof(struct blowfish_ctx),
+ .block_size=BLOWFISH_BLOCK_SIZE,
+ .key_size=BLOWFISH_KEY_SIZE,
+ .set_encrypt_key=&blowfish128_set_key,
+ .set_decrypt_key=&blowfish128_set_key,
+ .encrypt=&blowfish_encrypt,
+ .decrypt=&blowfish_decrypt
+};
+
+const struct nettle_cipher nettle_arcfour128={
+ .name="arcfour128",
+ .context_size=sizeof(struct arcfour_ctx),
+ .block_size=1,
+ .key_size=16,
+ .set_encrypt_key=&arcfour128_set_key,
+ .set_decrypt_key=&arcfour128_set_key,
+ .encrypt=&arcfour_crypt,
+ .decrypt=&arcfour_crypt
+};
+
+const struct nettle_cipher *own_list[]={&nettle_tea, &nettle_blowfish128, &nettle_arcfour128, NULL};
+
+/*
+void ecb(void *ctx, nettle_cipher_func f, size_t blocklen, size_t len, uint8_t *dst, uint8_t *src){
+ uint8_t *cur;
+ uint8_t *curd=dst;
+ for(cur=src; cur<src+len; cur+=blocklen){
+ f(ctx, blocklen, curd, cur);
+ curd+=blocklen;
+ }
+}
+
+void tea_encrypt(void *ctx
+*/
+
+const struct nettle_cipher* getCipherFromList(char *args, const struct nettle_cipher* const* nc){
+ for(; *nc!=NULL; nc++){
+ if(strcmp((*nc)->name, args)==0){
+ break;
+ }
+ }
+ return *nc;
+}
+
+const struct nettle_cipher* getCipher(char *args){
+ const struct nettle_cipher * nc;
+ nc=getCipherFromList(args, nettle_get_ciphers());
+ if(nc!=NULL){
+ return nc;
+ }
+ nc=getCipherFromList(args, own_list);
+ return nc;
+}
+
+enum MODE getMode(char *args){
+ if(strcmp(args, "CBC")==0){
+ return CBC;
+ }
+ else if(strcmp(args, "CTR")==0){
+ return CTR;
+ }
+ else if(strcmp(args, "CFB")==0){
+ return CFB;
+ }
+ else if(strcmp(args, "ECB")==0){
+ return ECB;
+ }
+ else{
+ return INVALID;
+ }
+}
+
+void parseKV(struct EncStage *es, char *args){
+ while(args!=NULL && *args!='\0'){
+ char *k=args;
+ char *kv=strstr(args, ",");
+ if(kv!=NULL){
+ *kv++='\0';
+ args=kv;
+ }
+ else{
+ args=NULL;
+ }
+ char *v=strstr(k, "=");
+ if(v==NULL){
+ es->key=(String){.str=k,.len=strlen(k)};
+ }
+ else{
+ *v++='\0';
+ if(strcmp("key", k)==0){
+ es->key=argString(v);
+ }
+ else if(strcmp("iv", k)==0){
+ es->iv=argString(v);
+ }
+ else{
+ fprintf(stderr, "Key %s not known\n", k);
+ }
+ }
+ }
+}
+
+int fillEncStage(struct EncStage *es, char *args){
+ switch(args[0]){
+ case '+':
+ es->dir=ENCRYPT;
+ break;
+ case '-':
+ es->dir=DECRYPT;
+ break;
+ default:
+ fprintf(stderr, "Malformed argument. + or - expected, got %c\n", args[0]);
+ return 1;
+ break;
+ }
+ args++;
+
+ char *cipher=strstr(args, ":");
+ if(cipher == NULL){
+ fprintf(stderr, "Colon (:) expected to denote the cipher mode\n");
+ return 1;
+ }
+ *cipher++='\0';
+ es->mode=getMode(args);
+ if(es->mode == INVALID){
+ fprintf(stderr, "Cipher mode %s unknown.\n", args);
+ return 1;
+ }
+
+ char *kv=strstr(cipher, ":");
+ if(kv!=NULL){
+ *kv++='\0';
+ parseKV(es, kv);
+ }
+
+ es->cipher=getCipher(cipher);
+ if(es->cipher == NULL){
+ fprintf(stderr, "cipher %s not known\n", cipher);
+ return 1;
+ }
+ return 0;
+}
+
+const char *modeToString(enum MODE m){
+ switch(m){
+ case CBC:
+ return "CBC";
+ case CTR:
+ return "CTR";
+ case CFB:
+ return "CFB";
+ case ECB:
+ return "ECB";
+ case INVALID:
+ default:
+ return "Invalid";
+
+ }
+}
+
+const char *encDirToString(enum DIRECTION ed){
+ switch(ed){
+ case ENCRYPT:
+ return "Encryption";
+ case DECRYPT:
+ return "Decryption";
+ default:
+ return "Invalid";
+ }
+}
+
+void fprintEncStage(FILE *f, struct EncStage *es){
+ fprintf(f, "%s using cipher %s in %s-Mode with key \"%s\" and IV \"%s\"\n", encDirToString(es->dir), es->cipher->name, modeToString(es->mode), es->key.str, es->iv.str);
+}
+
+void usage(){
+ const struct nettle_cipher * const *nc;
+ printf("Usage: nettle [-h | --help] <cipher_spec> [cipher_spec...]\n"\
+ "cipher_spec: direction ':' cipher [ ':' key_values ]\n"\
+ "direction: '+' | '-'\n"\
+ "cipher: string\n"\
+ "key_values: key_value | key_value ',' key_values\n"\
+ "key_value: key '=' value\n"\
+ "key: 'key' | 'iv'\n"\
+ "value: '@' file | string\n\n"
+ );
+ printf("Example: nettle -CBC:aes128:key=\"BENALOH PAILLIER\",iv=@iv.dat < HALOS.bin\n"\
+ "This prints to STDOUT a decryption in CBC mode using AES with 128 bits key length,\n"\
+ "using \"BENALOH PAILLIER\" as key and reading the initialization vector from the file iv.dat\n\n");
+ printf("Available ciphers names: \n");
+ for(nc=nettle_get_ciphers(); *nc!=NULL; nc++){
+ printf("%s\n", (*nc)->name);
+ }
+ for(nc=own_list; *nc!=NULL; nc++){
+ printf("%s\n", (*nc)->name);
+ }
+}
+
+void ECBEncrypt(void *state, struct EncStage *es){
+ es->cipher->encrypt(state, es->len, es->dst, es->src);
+}
+void ECBDecrypt(void *state, struct EncStage *es){
+ es->cipher->decrypt(state, es->len, es->dst, es->src);
+}
+void CBCEncrypt(void *state, struct EncStage *es){
+ cbc_encrypt(state, es->cipher->encrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+void CBCDecrypt(void *state, struct EncStage *es){
+ cbc_decrypt(state, es->cipher->decrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+void CTREncrypt(void *state, struct EncStage *es){
+ ctr_crypt(state, es->cipher->encrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+void CTRDecrypt(void *state, struct EncStage *es){
+ ctr_crypt(state, es->cipher->decrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+void CFBEncrypt(void *state, struct EncStage *es){
+ cfb_encrypt(state, es->cipher->encrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+void CFBDecrypt(void *state, struct EncStage *es){
+ cfb_decrypt(state, es->cipher->decrypt, es->cipher->block_size, es->iv.str, es->len, es->dst, es->src);
+}
+
+
+void execute(struct EncStage *es){
+ size_t ctx_s=es->cipher->context_size;
+ void *ctx=malloc(ctx_s);
+ memset(ctx, 0, ctx_s);
+
+ if(es->iv.len == 0){
+ es->iv.len=es->cipher->block_size;
+ es->iv.str=malloc(es->iv.len);
+ memset(es->iv.str, 0, es->iv.len);
+ }
+
+ switch(es->dir){
+ case ENCRYPT:
+ es->cipher->set_encrypt_key(ctx, es->key.str);
+ break;
+ case DECRYPT:
+ es->cipher->set_decrypt_key(ctx, es->key.str);
+ break;
+ }
+
+ switch(es->mode){
+ case ECB:
+ if(es->dir==ENCRYPT) ECBEncrypt(ctx, es); else ECBDecrypt(ctx, es);
+ break;
+ case CBC:
+ if(es->dir==ENCRYPT) CBCEncrypt(ctx, es); else CBCDecrypt(ctx, es);
+ break;
+ case CTR:
+ if(es->dir==ENCRYPT) CTREncrypt(ctx, es); else CTRDecrypt(ctx, es);
+ break;
+ case CFB:
+ if(es->dir==ENCRYPT) CFBEncrypt(ctx, es); else CFBDecrypt(ctx, es);
+ break;
+ }
+ free(ctx);
+}
+
+int main(int argc, char **argv){
+ if(argc>1 && (strcmp(argv[1], "-h")==0 || strcmp(argv[1], "--help")==0)){
+ usage();
+ return 0;
+ }
+ struct EncStage es;
+ int ret;
+ int i;
+ String s=readFile(stdin, SIZE_MAX);
+ String s2;
+ char *in=s.str;
+ char *out=NULL;
+ for(i=1; i<argc; i++){
+ memset(&es, 0, sizeof(typeof(es)));
+ ret=fillEncStage(&es, argv[i]);
+ if(ret!=0){
+ usage();
+ return 1;
+ }
+ fprintEncStage(stderr, &es);
+ //char *out=malloc(s.len);
+ //memset(out, 0x00, s.len);
+ es.len=s.len;
+ es.src=in;
+ es.dst=in;
+
+ execute(&es);
+ //char *tmp=in;
+ //in=out;
+ //free(tmp);
+ }
+ fwrite(in, 1, s.len, stdout);
+ return 0;
+}