nettleif

An encryption/decryption-Application using the nettle library
git clone git://xatko.vsos.ethz.ch/nettleif.git
Log | Files | Refs

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; +}