libidav/crypto.c

changeset 349
0b4ecadaf3f9
parent 267
171498cb2137
child 354
067ea2315a8a
--- 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

mercurial