--- a/libidav/crypto.c Sun Dec 17 10:53:08 2017 +0100 +++ b/libidav/crypto.c Sun Dec 17 13:20:01 2017 +0100 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2016 Olaf Wintermann. All rights reserved. + * Copyright 2017 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,11 +29,15 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <fcntl.h> #include <libidav/utils.h> -#include <openssl/rand.h> #include "crypto.h" +/* -------------------- OpenSSL Crypto Functions -------------------- */ +#ifdef DAV_USE_OPENSSL + #if OPENSSL_VERSION_NUMBER < 10000000 static EVP_CIPHER_CTX* create_evp_cipher_ctx() { @@ -324,6 +328,349 @@ } -void dav_get_hash(SHA256_CTX *sha256, unsigned char *buf) { +void dav_get_hash(SHA_CTX *sha256, unsigned char *buf) { SHA256_Final((unsigned char*)buf, sha256); } + +#endif + + +/* -------------------- Apple Crypto Functions -------------------- */ +#ifdef __APPLE__ + +#define RANDOM_BUFFER_LENGTH 256 +static char randbuf[RANDOM_BUFFER_LENGTH]; +static int rbufpos = RANDOM_BUFFER_LENGTH; + +int dav_rand_bytes(unsigned char *buf, size_t len) { + if(len + rbufpos > RANDOM_BUFFER_LENGTH) { + int devr = open("/dev/urandom", O_RDONLY); + if(devr == -1) { + return 1; + } + + if(read(devr, randbuf, RANDOM_BUFFER_LENGTH) < RANDOM_BUFFER_LENGTH) { + close(devr); + return 1; + } + + rbufpos = 0; + if(len > RANDOM_BUFFER_LENGTH) { + int err = 0; + if(read(devr, buf, len) < len) { + err = 1; + } + close(devr); + return err; + } + + close(devr); + } + + char *r = randbuf; + memcpy(buf, r + rbufpos, len); + rbufpos += len; + + return 0; +} + +AESDecrypter* aes_decrypter_new(DavKey *key, void *stream, dav_write_func write_func) { + AESDecrypter *dec = calloc(1, sizeof(AESDecrypter)); + CC_SHA256_Init(&dec->sha256); + dec->stream = stream; + dec->write = write_func; + dec->key = key; + dec->init = 0; + dec->ivpos = 0; + + return dec; +} + + +void aes_decrypter_init(AESDecrypter *dec) { + //EVP_CIPHER_CTX_init(&dec->ctx); + dec->init = 1; + + CCCryptorRef cryptor; + CCCryptorStatus status; + if(dec->key->type == DAV_KEY_AES128) { + status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, dec->key->data, dec->key->length, dec->ivtmp, &cryptor); + } else if(dec->key->type == DAV_KEY_AES256) { + status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, dec->key->data, dec->key->length, dec->ivtmp, &cryptor); + } else { + fprintf(stderr, "unknown key type\n"); + exit(-1); + } + dec->ctx = cryptor; +} + +size_t aes_write(const void *buf, size_t s, size_t n, AESDecrypter *dec) { + int len = s*n; + if(!dec->init) { + size_t n = 16 - dec->ivpos; + size_t cp = n > len ? len : n; + memcpy(dec->ivtmp + dec->ivpos, buf, cp); + dec->ivpos += cp; + if(dec->ivpos >= 16) { + aes_decrypter_init(dec); + } + if(len == cp) { + return len; + } else { + buf = (char*)buf + cp; + len -= cp; + } + } + + int outlen = len + 16; + unsigned char *out = malloc(outlen); + + CCCryptorStatus status; + size_t avail = outlen; + size_t moved = 0; + status = CCCryptorUpdate(dec->ctx, buf, len, out, avail, &moved); + + ssize_t wlen = dec->write(out, 1, moved, dec->stream); + CC_SHA256_Update(&dec->sha256, out, wlen); + free(out); + return (s*n) / s; +} + +void aes_decrypter_shutdown(AESDecrypter *dec) { + if(dec->init) { + void *out = malloc(128); + size_t len = 0; + //EVP_DecryptFinal_ex(dec->ctx, out, &len); + CCCryptorFinal(dec->ctx, out, 128, &len); + + + dec->write(out, 1, len, dec->stream); + CC_SHA256_Update(&dec->sha256, out, len); + free(out); + //EVP_CIPHER_CTX_cleanup(&dec->ctx); + //EVP_CIPHER_CTX_free(dec->ctx); + } +} + +void aes_decrypter_close(AESDecrypter *dec) { + +} + +AESEncrypter* aes_encrypter_new(DavKey *key, void *stream, dav_read_func read_func) { + unsigned char *iv = malloc(16); + if(dav_rand_bytes(iv, 16)) { + return NULL; + } + + CCCryptorRef cryptor; + CCCryptorStatus status; + if(key->type == DAV_KEY_AES128) { + status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, key->data, key->length, iv, &cryptor); + } else if(key->type == DAV_KEY_AES256) { + status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key->data, key->length, iv, &cryptor); + } else { + free(iv); + return NULL; + } + + AESEncrypter *enc = malloc(sizeof(AESEncrypter)); + enc->ctx = cryptor; + CC_SHA256_Init(&enc->sha256); + enc->stream = stream; + enc->read = read_func; + enc->tmp = NULL; + enc->tmplen = 0; + enc->tmpoff = 0; + enc->end = 0; + enc->iv = iv; + enc->ivlen = 16; + + return enc; +} + +size_t aes_read(void *buf, size_t s, size_t n, AESEncrypter *enc) { + size_t len = s*n; + if(enc->tmp) { + size_t tmp_diff = enc->tmplen - enc->tmpoff; + size_t cp_len = tmp_diff > len ? len : tmp_diff; + memcpy(buf, enc->tmp + enc->tmpoff, cp_len); + enc->tmpoff += cp_len; + if(enc->tmpoff >= enc->tmplen) { + free(enc->tmp); + enc->tmp = NULL; + enc->tmplen = 0; + enc->tmpoff = 0; + } + return cp_len / s; + } + + if(enc->end) { + return 0; + } + + void *in = malloc(len); + size_t in_len = enc->read(in, 1, len, enc->stream); + + CC_SHA256_Update(&enc->sha256, in, in_len); + + unsigned char *out = NULL; + size_t outlen = 0; + size_t ivl = enc->ivlen; + if(in_len != 0) { + outlen = len + 16; + out = malloc(outlen + ivl); + if(enc->iv) { + memcpy(out, enc->iv, ivl); + } + + CCCryptorStatus status; + size_t avail = outlen; + status = CCCryptorUpdate(enc->ctx, in, in_len, out + ivl, avail, &outlen); + + free(in); + } else { + out = malloc(32); + CCCryptorStatus status; + size_t avail = outlen; + status = CCCryptorFinal(enc->ctx, out, 32, &outlen); + enc->end = 1; + free(in); + } + enc->tmp = (char*)out; + enc->tmplen = outlen + ivl; + enc->tmpoff = 0; + + if(enc->iv) { + free(enc->iv); + enc->iv = NULL; + enc->ivlen = 0; + } + + return aes_read(buf, s, n, enc); +} + +void aes_encrypter_close(AESEncrypter *enc) { + if(enc->tmp) { + free(enc->tmp); + } + if(enc->iv) { + free(enc->iv); + } + // TODO: cleanup cryptor + free(enc); +} + +char* aes_encrypt(char *in, size_t len, DavKey *key) { + unsigned char iv[16]; + if(dav_rand_bytes(iv, 16)) { + return NULL; + } + + CCCryptorRef cryptor; + CCCryptorStatus status; + if(key->type == DAV_KEY_AES128) { + status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, key->data, key->length, iv, &cryptor); + } else if(key->type == DAV_KEY_AES256) { + status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key->data, key->length, iv, &cryptor); + } else { + return NULL; + } + + if(status != kCCSuccess) { + return NULL; + } + + int buflen = len + 64; + char *buf = calloc(1, buflen); + memcpy(buf, iv, 16); + + int pos = 16; + size_t avail = buflen - 16; + size_t moved; + char *out = buf + 16; + + status = CCCryptorUpdate(cryptor, in, + len, out, avail, + &moved); + if(status != kCCSuccess) { + free(buf); + return NULL; + } + + pos += moved; + avail -= moved; + out += moved; + + status = CCCryptorFinal(cryptor, out, avail, &moved); + if(status != kCCSuccess) { + free(buf); + return NULL; + } + + pos += moved; + + char *b64enc = util_base64encode(buf, pos); + free(buf); + + return b64enc; +} + +char* aes_decrypt(char *in, size_t *len, DavKey *key) { + int inlen; + unsigned char *buf = (unsigned char*)util_base64decode_len(in, &inlen); + + CCCryptorRef cryptor; + CCCryptorStatus status; + if(key->type == DAV_KEY_AES128) { + status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, key->data, key->length, buf, &cryptor); + } else if(key->type == DAV_KEY_AES256) { + status = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding, key->data, key->length, buf, &cryptor); + } else { + free(buf); + return NULL; + } + + if(status != kCCSuccess) { + free(buf); + return NULL; + } + + char *out = malloc(inlen + 1); + size_t outavail = inlen; + size_t outlen = 0; + + unsigned char *inbuf = buf + 16; + inlen -= 16; + + size_t moved = 0; + status = CCCryptorUpdate(cryptor, inbuf, inlen, out, outavail, &moved); + if(status != kCCSuccess) { + free(buf); + free(out); + // TODO cryptor + return NULL; + } + + outlen += moved; + outavail -= moved; + + status = CCCryptorFinal(cryptor, out + outlen, outavail, &moved); + if(status != kCCSuccess) { + free(buf); + free(out); + // TODO cryptor + return NULL; + } + + outlen += moved; + out[outlen] = 0; + + *len = outlen; + return out; +} + +void dav_get_hash(DAV_SHA_CTX *sha256, unsigned char *buf) { + CC_SHA256_Final(buf, sha256); +} + +#endif