#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "utils.h"
#include "crypto.h"
#ifdef DAV_USE_OPENSSL
#if OPENSSL_VERSION_NUMBER < 0x10000000L
static EVP_CIPHER_CTX* create_evp_cipher_ctx() {
EVP_CIPHER_CTX *ctx = malloc(
sizeof(
EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(ctx);
return ctx;
}
static void free_evp_cipher_ctx(
EVP_CIPHER_CTX *ctx) {
EVP_CIPHER_CTX_cleanup(ctx);
free(ctx);
}
#define EVP_CIPHER_CTX_new() create_evp_cipher_ctx()
#define EVP_CIPHER_CTX_free(ctx) free_evp_cipher_ctx(ctx)
#endif
int dav_rand_bytes(
unsigned char *buf,
size_t len) {
return !RAND_bytes(buf, len);
}
AESDecrypter* aes_decrypter_new(DavKey *key,
void *stream, dav_write_func write_func) {
AESDecrypter *dec = calloc(
1,
sizeof(AESDecrypter));
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) {
dec->ctx = EVP_CIPHER_CTX_new();
dec->init =
1;
if(dec->key->type ==
DAV_KEY_AES128) {
EVP_DecryptInit_ex(
dec->ctx,
EVP_aes_128_cbc(),
NULL,
dec->key->data,
dec->ivtmp);
}
else if(dec->key->type ==
DAV_KEY_AES256) {
EVP_DecryptInit_ex(
dec->ctx,
EVP_aes_256_cbc(),
NULL,
dec->key->data,
dec->ivtmp);
}
else {
fprintf(stderr,
"unknown key type\n");
exit(-
1);
}
}
size_t aes_write(
const void *buf,
size_t s,
size_t n, AESDecrypter *dec) {
int len = s*n;
if(!dec->init) {
size_t m =
16 - dec->ivpos;
size_t cp = m > len ? len : m;
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);
EVP_DecryptUpdate(dec->ctx, out, &outlen, buf, len);
ssize_t wlen = dec->write(out,
1, outlen, dec->stream);
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);
int len =
0;
EVP_DecryptFinal_ex(dec->ctx, out, &len);
dec->write(out,
1, len, dec->stream);
SHA256_Update(&dec->sha256, out, len);
free(out);
EVP_CIPHER_CTX_free(dec->ctx);
}
}
void aes_decrypter_close(AESDecrypter *dec) {
free(dec);
}
AESEncrypter* aes_encrypter_new(DavKey *key,
void *stream, dav_read_func read_func, dav_seek_func seek_func) {
unsigned char *iv = malloc(
16);
if(!RAND_bytes(iv,
16)) {
free(iv);
return NULL;
}
AESEncrypter *enc = malloc(
sizeof(AESEncrypter));
SHA256_Init(&enc->sha256);
enc->stream = stream;
enc->read = read_func;
enc->seek = seek_func;
enc->tmp =
NULL;
enc->tmplen =
0;
enc->tmpoff =
0;
enc->end =
0;
enc->iv = iv;
enc->ivlen =
16;
enc->ctx = EVP_CIPHER_CTX_new();
if(key->type ==
DAV_KEY_AES128) {
EVP_EncryptInit_ex(enc->ctx, EVP_aes_128_cbc(),
NULL, key->data, enc->iv);
}
else if(key->type ==
DAV_KEY_AES256) {
EVP_EncryptInit_ex(enc->ctx, EVP_aes_256_cbc(),
NULL, key->data, enc->iv);
}
else {
fprintf(stderr,
"unknown key type\n");
exit(-
1);
}
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);
SHA256_Update(&enc->sha256, in, in_len);
unsigned char *out =
NULL;
int outlen =
0;
size_t ivl = enc->ivlen;
if(in_len !=
0) {
outlen = len +
32;
out = malloc(outlen + ivl);
if(ivl >
0) {
memcpy(out, enc->iv, ivl);
}
EVP_EncryptUpdate(enc->ctx, out + ivl, &outlen, in, in_len);
}
else {
out = malloc(
16);
EVP_EncryptFinal_ex(enc->ctx, out, &outlen);
enc->end =
1;
}
enc->tmp = (
char*)out;
enc->tmplen = outlen + ivl;
enc->tmpoff =
0;
if(enc->ivlen >
0) {
enc->ivlen =
0;
}
free(in);
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);
}
EVP_CIPHER_CTX_free(enc->ctx);
free(enc);
}
int aes_encrypter_reset(AESEncrypter *enc,
curl_off_t offset,
int origin) {
if(origin !=
SEEK_SET || offset !=
0 || !enc->seek) {
return CURL_SEEKFUNC_CANTSEEK;
}
enc->ivlen =
16;
if(enc->seek(enc->stream,
0,
SEEK_SET) !=
0) {
return CURL_SEEKFUNC_FAIL;
}
return CURL_SEEKFUNC_OK;
}
char* aes_encrypt(
const char *in,
size_t len, DavKey *key) {
unsigned char iv[
16];
if(!RAND_bytes(iv,
16)) {
return NULL;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if(key->type ==
DAV_KEY_AES128) {
EVP_EncryptInit_ex(
ctx,
EVP_aes_128_cbc(),
NULL,
(
unsigned char*)key->data,
iv);
}
else if(key->type ==
DAV_KEY_AES256) {
EVP_EncryptInit_ex(
ctx,
EVP_aes_256_cbc(),
NULL,
(
unsigned char*)key->data,
iv);
}
else {
EVP_CIPHER_CTX_free(ctx);
return NULL;
}
int buflen = len +
64;
unsigned char *buf = calloc(
1, buflen);
memcpy(buf, iv,
16);
int l = buflen -
16;
EVP_EncryptUpdate(ctx, buf +
16, &l, (
unsigned char*)in, len);
int f =
0;
EVP_EncryptFinal_ex(ctx, buf +
16 + l, &f);
char *out = util_base64encode((
char*)buf,
16 + l + f);
free(buf);
EVP_CIPHER_CTX_free(ctx);
return out;
}
char* aes_decrypt(
const char *in,
size_t *length, DavKey *key) {
int len;
unsigned char *buf = (
unsigned char*)util_base64decode_len(in, &len);
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if(key->type ==
DAV_KEY_AES128) {
EVP_DecryptInit_ex(
ctx,
EVP_aes_128_cbc(),
NULL,
key->data,
buf);
}
else if(key->type ==
DAV_KEY_AES256) {
EVP_DecryptInit_ex(
ctx,
EVP_aes_256_cbc(),
NULL,
key->data,
buf);
}
else {
EVP_CIPHER_CTX_free(ctx);
return NULL;
}
unsigned char *out = malloc(len +
1);
int outlen = len;
unsigned char *in_buf = buf +
16;
int inlen = len -
16;
int f =
0;
EVP_DecryptUpdate(ctx, out, &outlen, in_buf, inlen);
EVP_DecryptFinal_ex(ctx, out + outlen, &f);
out[outlen + f] =
'\0';
free(buf);
EVP_CIPHER_CTX_free(ctx);
*length = outlen + f;
return (
char*)out;
}
void dav_get_hash(
DAV_SHA_CTX *sha256,
unsigned char *buf){
SHA256_Final((
unsigned char*)buf, sha256);
}
char* dav_create_hash(
const char *data,
size_t len) {
unsigned char hash[
DAV_SHA256_DIGEST_LENGTH];
DAV_SHA_CTX ctx;
SHA256_Init(&ctx);
SHA256_Update(&ctx, data, len);
SHA256_Final(hash, &ctx);
return util_hexstr(hash,
DAV_SHA256_DIGEST_LENGTH);
}
DAV_SHA_CTX* dav_hash_init(
void) {
DAV_SHA_CTX *ctx = malloc(
sizeof(
DAV_SHA_CTX));
SHA256_Init(ctx);
return ctx;
}
void dav_hash_update(
DAV_SHA_CTX *ctx,
const char *data,
size_t len) {
SHA256_Update(ctx, data, len);
}
void dav_hash_final(
DAV_SHA_CTX *ctx,
unsigned char *buf) {
SHA256_Final(buf, ctx);
free(ctx);
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static int crypto_pw2key_error =
0;
DavKey* dav_pw2key(
const char *password,
const unsigned char *salt,
int saltlen,
int pwfunc,
int enc) {
if(!crypto_pw2key_error) {
fprintf(stderr,
"Error: password key derivation not supported on this platform: openssl to old\n");
crypto_pw2key_error =
1;
}
return 0;
}
#else
DavKey* dav_pw2key(
const char *password,
const unsigned char *salt,
int saltlen,
int pwfunc,
int enc) {
if(!password) {
return NULL;
}
size_t len = strlen(password);
if(len ==
0) {
return NULL;
}
unsigned char keydata[
32];
int keylen =
32;
switch(enc) {
case DAV_KEY_AES128: keylen =
16;
break;
case DAV_KEY_AES256: keylen =
32;
break;
default:
return NULL;
}
switch(pwfunc) {
case DAV_PWFUNC_PBKDF2_SHA256: {
PKCS5_PBKDF2_HMAC(
password,
len,
salt,
saltlen,
DAV_CRYPTO_ITERATION_COUNT,
EVP_sha256(),
keylen,
keydata);
break;
}
case DAV_PWFUNC_PBKDF2_SHA512: {
PKCS5_PBKDF2_HMAC(
password,
len,
salt,
saltlen,
DAV_CRYPTO_ITERATION_COUNT,
EVP_sha512(),
keylen,
keydata);
break;
}
default:
return NULL;
}
DavKey *key = malloc(
sizeof(DavKey));
key->data = malloc(keylen);
key->length = keylen;
key->name =
NULL;
key->type = enc;
memcpy(key->data, keydata, keylen);
return key;
}
#endif
#endif
#ifdef DAV_CRYPTO_COMMON_CRYPTO
#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) {
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;
CCCryptorFinal(dec->ctx, out,
128, &len);
dec->write(out,
1, len, dec->stream);
CC_SHA256_Update(&dec->sha256, out, len);
free(out);
}
}
void aes_decrypter_close(AESDecrypter *dec) {
}
AESEncrypter* aes_encrypter_new(DavKey *key,
void *stream, dav_read_func read_func, dav_seek_func seek_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->seek = seek_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 +
32;
out = malloc(outlen + ivl);
if(ivl >
0) {
memcpy(out, enc->iv, ivl);
}
CCCryptorStatus status;
size_t avail = outlen;
status = CCCryptorUpdate(enc->ctx, in, in_len, out + ivl, avail, &outlen);
}
else {
out = malloc(
32);
CCCryptorStatus status;
size_t avail = outlen;
status = CCCryptorFinal(enc->ctx, out,
32, &outlen);
enc->end =
1;
}
enc->tmp = (
char*)out;
enc->tmplen = outlen + ivl;
enc->tmpoff =
0;
if(enc->ivlen >
0) {
enc->ivlen =
0;
}
free(in);
return aes_read(buf, s, n, enc);
}
int aes_encrypter_reset(AESEncrypter *enc,
curl_off_t offset,
int origin) {
if(origin !=
SEEK_SET || offset !=
0 || !enc->seek) {
return CURL_SEEKFUNC_CANTSEEK;
}
enc->ivlen =
16;
if(enc->seek(enc->stream,
0,
SEEK_SET) !=
0) {
return CURL_SEEKFUNC_FAIL;
}
return CURL_SEEKFUNC_OK;
}
void aes_encrypter_close(AESEncrypter *enc) {
if(enc->tmp) {
free(enc->tmp);
}
if(enc->iv) {
free(enc->iv);
}
free(enc);
}
char* aes_encrypt(
const 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(
const 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);
return NULL;
}
outlen += moved;
outavail -= moved;
status = CCCryptorFinal(cryptor, out + outlen, outavail, &moved);
if(status != kCCSuccess) {
free(buf);
free(out);
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);
}
char* dav_create_hash(
const char *data,
size_t len) {
unsigned char hash[
DAV_SHA256_DIGEST_LENGTH];
CC_SHA256((
const unsigned char*)data, len, hash);
return util_hexstr(hash,
DAV_SHA256_DIGEST_LENGTH);
}
DAV_SHA_CTX* dav_hash_init(
void) {
DAV_SHA_CTX *ctx = malloc(
sizeof(
DAV_SHA_CTX));
CC_SHA256_Init(ctx);
return ctx;
}
void dav_hash_update(
DAV_SHA_CTX *ctx,
const char *data,
size_t len) {
CC_SHA256_Update(ctx, data, len);
}
void dav_hash_final(
DAV_SHA_CTX *ctx,
unsigned char *buf) {
CC_SHA256_Final(buf, ctx);
free(ctx);
}
DavKey* dav_pw2key(
const char *password,
const unsigned char *salt,
int saltlen,
int pwfunc,
int enc) {
if(!password) {
return NULL;
}
size_t len = strlen(password);
if(len ==
0) {
return NULL;
}
unsigned char keydata[
32];
int keylen =
32;
switch(enc) {
case DAV_KEY_AES128: keylen =
16;
break;
case DAV_KEY_AES256: keylen =
32;
break;
default:
return NULL;
}
switch(pwfunc) {
case DAV_PWFUNC_PBKDF2_SHA256: {
int result = CCKeyDerivationPBKDF(
kCCPBKDF2,
password,
len,
salt,
saltlen,
kCCPRFHmacAlgSHA256,
DAV_CRYPTO_ITERATION_COUNT,
keydata,
keylen);
if(result) {
return NULL;
}
break;
}
case DAV_PWFUNC_PBKDF2_SHA512: {
int result = CCKeyDerivationPBKDF(
kCCPBKDF2,
password,
len,
salt,
saltlen,
kCCPRFHmacAlgSHA512,
DAV_CRYPTO_ITERATION_COUNT,
keydata,
keylen);
if(result) {
return NULL;
}
break;
}
default:
return NULL;
}
DavKey *key = malloc(
sizeof(DavKey));
key->data = malloc(keylen);
key->length = keylen;
key->name =
NULL;
key->type = enc;
memcpy(key->data, keydata, keylen);
return key;
}
#endif
#ifdef DAV_CRYPTO_CNG
static void cng_cleanup(
BCRYPT_ALG_HANDLE hAesAlg,
BCRYPT_KEY_HANDLE hKey,
BCRYPT_HASH_HANDLE hHash,
void *pbObject) {
if(hAesAlg) {
BCryptCloseAlgorithmProvider(hAesAlg,
0);
}
if(hKey) {
BCryptDestroyKey(hKey);
}
if(hHash) {
BCryptDestroyHash(hHash);
}
if(pbObject) {
free(pbObject);
}
}
static int cng_init_key(
BCRYPT_ALG_HANDLE *alg,
BCRYPT_KEY_HANDLE *key,
void **keyobj, DavKey *aesKey) {
BCRYPT_ALG_HANDLE hAesAlg =
NULL;
BCRYPT_KEY_HANDLE hKey =
NULL;
void *pbKeyObject =
NULL;
ULONG keyObjectLength =
0;
ULONG result =
0;
if(!aesKey) {
return 1;
}
ULONG aesKeyLength =
0;
if(aesKey->type ==
DAV_KEY_AES128) {
aesKeyLength =
16;
}
else if(aesKey->type ==
DAV_KEY_AES256) {
aesKeyLength =
32;
}
if(aesKeyLength > aesKey->length || !aesKey->data) {
return 1;
}
if(BCryptOpenAlgorithmProvider(&hAesAlg,
BCRYPT_AES_ALGORITHM,
NULL,
0)) {
fprintf(stderr,
"Error: BCryptOpenAlgorithmProvider failed\n");
return 1;
}
if(BCryptGetProperty(hAesAlg,
BCRYPT_OBJECT_LENGTH, (
PUCHAR)&keyObjectLength,
sizeof(
DWORD), &result,
0)) {
fprintf(stderr,
"Error: BCrypt: Cannot get BCRYPT_OBJECT_LENGTH\n");
cng_cleanup(hAesAlg, hKey,
NULL, pbKeyObject);
return 1;
}
if(BCryptSetProperty(hAesAlg,
BCRYPT_CHAINING_MODE, (
PBYTE)
BCRYPT_CHAIN_MODE_CBC,
sizeof(
BCRYPT_CHAIN_MODE_CBC),
0)) {
fprintf(stderr,
"Error: BCrypt: Cannot set CBC mode\n");
cng_cleanup(hAesAlg, hKey,
NULL, pbKeyObject);
return 1;
}
pbKeyObject = calloc(
1, keyObjectLength);
if(!pbKeyObject) {
cng_cleanup(hAesAlg, hKey,
NULL, pbKeyObject);
return 1;
}
if(BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject, keyObjectLength, aesKey->data, aesKeyLength,
0)) {
fprintf(stderr,
"Error: BCrypt: Cannot set key\n");
cng_cleanup(hAesAlg, hKey,
NULL, pbKeyObject);
return 1;
}
*alg = hAesAlg;
*key = hKey;
*keyobj = pbKeyObject;
return 0;
}
static int cng_hash_init(WinBCryptSHACTX *ctx) {
if(BCryptOpenAlgorithmProvider(&ctx->hAlg,
BCRYPT_SHA256_ALGORITHM,
NULL,
0)) {
fprintf(stderr,
"Error: BCryptOpenAlgorithmProvider failed\n");
return 1;
}
ULONG hashObjectLen;
ULONG result;
if(BCryptGetProperty(ctx->hAlg,
BCRYPT_OBJECT_LENGTH, (
PBYTE)&hashObjectLen,
sizeof(
DWORD), &result,
0)) {
cng_cleanup(ctx->hAlg,
NULL,
NULL,
NULL);
return 1;
}
ctx->pbHashObject = calloc(
1, hashObjectLen);
if(BCryptCreateHash(ctx->hAlg, &ctx->hHash, ctx->pbHashObject, hashObjectLen,
NULL,
0,
0)) {
cng_cleanup(ctx->hAlg,
NULL, ctx->hHash, ctx->pbHashObject);
return 1;
}
return 0;
}
int dav_rand_bytes(
unsigned char *buf,
size_t len) {
if(BCryptGenRandom(
NULL, (
unsigned char*)buf, (
ULONG)len,
BCRYPT_USE_SYSTEM_PREFERRED_RNG)) {
return 1;
}
return 0;
}
AESDecrypter* aes_decrypter_new(DavKey *key,
void *stream, dav_write_func write_func) {
AESDecrypter *dec = calloc(
1,
sizeof(AESDecrypter));
if(!dec) {
return NULL;
}
if(cng_hash_init(&dec->sha256)) {
free(dec);
return NULL;
}
dec->stream = stream;
dec->write = write_func;
dec->key = key;
dec->init =
0;
dec->ivpos =
0;
return dec;
}
static void aes_decrypter_init(AESDecrypter *dec) {
if(cng_init_key(&dec->ctx.hAlg, &dec->ctx.hKey, &dec->ctx.pbKeyObject, dec->key)) {
fprintf(stderr,
"Error: cng_init_key failed\n");
exit(-
1);
}
memcpy(dec->ctx.pbIV, dec->ivtmp,
16);
}
size_t aes_write(
const void *buf,
size_t s,
size_t n, AESDecrypter *dec) {
int len = s*n;
if(!dec->init) {
dec->init =
1;
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;
}
}
size_t cbufalloc = len +
64;
ULONG clen =
0;
char *cbuf = malloc(cbufalloc);
if(dec->ctx.buflen >
0) {
memcpy(cbuf, dec->ctx.buf, dec->ctx.buflen);
clen = dec->ctx.buflen;
}
memcpy(cbuf + clen, buf, len);
clen += len;
int remaining = clen %
16;
if(remaining ==
0) {
remaining =
16;
}
clen -= remaining;
memcpy(dec->ctx.buf, cbuf + clen, remaining);
dec->ctx.buflen = remaining;
ULONG outlen = clen +
32;
if(clen >
0) {
unsigned char* out = malloc(outlen);
ULONG enc_len =
0;
ULONG status = BCryptDecrypt(dec->ctx.hKey, cbuf, clen,
NULL, dec->ctx.pbIV,
16, out, outlen, &enc_len,
0);
if(status >
0) {
fprintf(stderr,
"Error: BCryptDecrypt failed: 0x%X\n", status);
free(out);
free(cbuf);
return 0;
}
outlen = enc_len;
dec->write(out,
1, outlen, dec->stream);
BCryptHashData(dec->sha256.hHash, out, outlen,
0);
free(out);
}
free(cbuf);
return (s*n) / s;
}
void aes_decrypter_shutdown(AESDecrypter *dec) {
if(dec->init && dec->ctx.buflen >
0) {
ULONG outlen =
64;
char out[
64];
if(BCryptDecrypt(dec->ctx.hKey, dec->ctx.buf, dec->ctx.buflen,
NULL, dec->ctx.pbIV,
16, out, outlen, &outlen,
BCRYPT_BLOCK_PADDING)) {
fprintf(stderr,
"Error: BCryptDecrypt failed\n");
return;
}
dec->write(out,
1, outlen, dec->stream);
BCryptHashData(dec->sha256.hHash, out, outlen,
0);
}
}
void aes_decrypter_close(AESDecrypter *dec) {
cng_cleanup(dec->ctx.hAlg, dec->ctx.hKey,
NULL, dec->ctx.pbKeyObject);
cng_cleanup(dec->sha256.hAlg,
NULL, dec->sha256.hHash, dec->sha256.pbHashObject);
free(dec);
}
AESEncrypter* aes_encrypter_new(DavKey *key,
void *stream, dav_read_func read_func, dav_seek_func seek_func) {
unsigned char *iv = malloc(
16);
if(dav_rand_bytes(iv,
16)) {
free(iv);
return NULL;
}
AESEncrypter *enc = calloc(
1,
sizeof(AESEncrypter));
if(cng_hash_init(&enc->sha256)) {
free(iv);
free(enc);
return NULL;
}
enc->stream = stream;
enc->read = read_func;
enc->seek = seek_func;
enc->tmp =
NULL;
enc->tmplen =
0;
enc->tmpoff =
0;
enc->end =
0;
enc->iv = iv;
enc->ivlen =
0;
if(cng_init_key(&enc->ctx.hAlg, &enc->ctx.hKey, &enc->ctx.pbKeyObject, key)) {
fprintf(stderr,
"Error: cng_init_key failed\n");
exit(-
1);
}
enc->ctx.buflen =
0;
memcpy(enc->ctx.pbIV, iv,
16);
return enc;
}
size_t aes_read(
void *buf,
size_t s,
size_t n, AESEncrypter *enc) {
size_t len = s*n;
size_t nread =
0;
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->ivlen <
16) {
size_t copy_iv_len =
16 - enc->ivlen;
copy_iv_len = len > copy_iv_len ? copy_iv_len : len;
memcpy(buf, enc->iv, copy_iv_len);
(
char*)buf += copy_iv_len;
len -= copy_iv_len;
nread = copy_iv_len;
enc->ivlen += copy_iv_len;
if(len ==
0) {
return copy_iv_len / s;
}
}
if(enc->end) {
return 0;
}
size_t remaining = len %
16;
len -= remaining;
if(len >
256) {
len -=
16;
}
size_t inalloc = len;
ULONG inlen =
0;
unsigned char *in = malloc(inalloc);
while(inlen < inalloc) {
size_t r = enc->read(in + inlen,
1, inalloc - inlen, enc->stream);
if(r ==
0) {
enc->end =
1;
break;
}
inlen += r;
}
if(inlen ==
0) {
return nread / s;
}
BCryptHashData(enc->sha256.hHash, in, inlen,
0);
ULONG outalloc = inlen +
16;
ULONG outlen =
0;
char *out = malloc(outalloc);
int flags =
0;
if(inlen %
16 !=
0) {
enc->end =
1;
}
if(enc->end) {
flags =
BCRYPT_BLOCK_PADDING;
}
if(BCryptEncrypt(enc->ctx.hKey, in, inlen,
NULL, enc->ctx.pbIV,
16, out, outalloc, &outlen, flags)) {
fprintf(stderr,
"Error: BCryptEncrypt failed\n");
}
if(outlen > len) {
size_t tmplen = outlen - len;
char *tmp = malloc(tmplen);
memcpy(tmp, out+len, tmplen);
enc->tmp = tmp;
enc->tmplen = tmplen;
enc->tmpoff =
0;
outlen = len;
}
memcpy(buf, out, outlen);
nread += outlen;
free(in);
free(out);
return nread / s;
}
void aes_encrypter_close(AESEncrypter *enc) {
enc->end =
1;
}
int aes_encrypter_reset(AESEncrypter *enc,
curl_off_t offset,
int origin) {
if(origin !=
SEEK_SET || offset !=
0 || !enc->seek) {
return CURL_SEEKFUNC_CANTSEEK;
}
enc->ivlen =
0;
memcpy(enc->ctx.pbIV, enc->iv,
16);
if(enc->seek(enc->stream,
0,
SEEK_SET) !=
0) {
return CURL_SEEKFUNC_FAIL;
}
return CURL_SEEKFUNC_OK;
}
char* aes_encrypt(
const char *in,
size_t len, DavKey *key) {
char iv[
16];
if(dav_rand_bytes(iv,
16)) {
return NULL;
}
BCRYPT_ALG_HANDLE hAlg =
NULL;
BCRYPT_KEY_HANDLE hKey =
NULL;
void *pbKeyObject =
NULL;
if(cng_init_key(&hAlg, &hKey, &pbKeyObject, key)) {
return NULL;
}
ULONG outlen = len +
128;
char *out = malloc(outlen);
memcpy(out, iv,
16);
char *encbuf = out +
16;
ULONG enclen = outlen -
16;
ULONG encoutlen =
0;
if(BCryptEncrypt(hKey, (
PUCHAR)in, len,
NULL, (
PUCHAR)iv,
16, encbuf, enclen, &encoutlen,
BCRYPT_BLOCK_PADDING)) {
fprintf(stderr,
"Error: BCryptEncrypt failed\n");
cng_cleanup(hAlg, hKey,
NULL, pbKeyObject);
free(out);
return NULL;
}
outlen = encoutlen +
16;
char *outstr = util_base64encode(out, outlen);
cng_cleanup(hAlg, hKey,
NULL, pbKeyObject);
free(out);
return outstr;
}
char* aes_decrypt(
const char *in,
size_t *len, DavKey *key) {
BCRYPT_ALG_HANDLE hAlg =
NULL;
BCRYPT_KEY_HANDLE hKey =
NULL;
void *pbKeyObject =
NULL;
if(cng_init_key(&hAlg, &hKey, &pbKeyObject, key)) {
return NULL;
}
int inlen;
unsigned char *buf = (
unsigned char*)util_base64decode_len(in, &inlen);
if(inlen <
16 || !buf) {
cng_cleanup(hAlg, hKey,
NULL, pbKeyObject);
if(buf) {
free(buf);
}
return NULL;
}
char iv[
16];
memcpy(iv, buf,
16);
char *data = buf +
16;
size_t datalen = inlen -
16;
ULONG outlen = inlen;
char *out = malloc(outlen +
1);
if(BCryptDecrypt(hKey, data, datalen,
NULL, iv,
16, out, outlen, &outlen,
BCRYPT_BLOCK_PADDING)) {
cng_cleanup(hAlg, hKey,
NULL, pbKeyObject);
free(out);
free(buf);
return NULL;
}
out[outlen] =
0;
*len = (
size_t)outlen;
return out;
}
void dav_get_hash(
DAV_SHA_CTX *sha256,
unsigned char *buf) {
BCryptFinishHash(sha256->hHash, buf,
DAV_SHA256_DIGEST_LENGTH,
0);
}
char* dav_create_hash(
const char *data,
size_t len) {
unsigned char hash[
DAV_SHA256_DIGEST_LENGTH];
DAV_SHA_CTX *ctx = dav_hash_init();
if(ctx) {
dav_hash_update(ctx, data, len);
dav_hash_final(ctx, hash);
}
return util_hexstr(hash,
DAV_SHA256_DIGEST_LENGTH);
}
DAV_SHA_CTX* dav_hash_init(
void) {
DAV_SHA_CTX *ctx = malloc(
sizeof(
DAV_SHA_CTX));
if(!ctx) {
return NULL;
}
if(cng_hash_init(ctx)) {
free(ctx);
return NULL;
}
return ctx;
}
void dav_hash_update(
DAV_SHA_CTX *ctx,
const char *data,
size_t len) {
BCryptHashData(ctx->hHash, (
PUCHAR)data, len,
0);
}
void dav_hash_final(
DAV_SHA_CTX *ctx,
unsigned char *buf) {
BCryptFinishHash(ctx->hHash, (
PUCHAR)buf,
DAV_SHA256_DIGEST_LENGTH,
0);
cng_cleanup(ctx->hAlg,
NULL, ctx->hHash, ctx->pbHashObject);
free(ctx);
}
DavKey* dav_pw2key(
const char *password,
const unsigned char *salt,
int saltlen,
int pwfunc,
int enc) {
if(!password) {
return NULL;
}
size_t len = strlen(password);
if(len ==
0) {
return NULL;
}
unsigned char keydata[
128];
int keylen =
32;
switch(enc) {
case DAV_KEY_AES128: keylen =
16;
break;
case DAV_KEY_AES256: keylen =
32;
break;
default:
return NULL;
}
LPCWSTR algid;
switch(pwfunc) {
case DAV_PWFUNC_PBKDF2_SHA256: algid =
BCRYPT_SHA256_ALGORITHM;
break;
case DAV_PWFUNC_PBKDF2_SHA512: algid =
BCRYPT_SHA512_ALGORITHM;
break;
default:
return NULL;
}
BCRYPT_ALG_HANDLE hAlg;
ULONG status = BCryptOpenAlgorithmProvider(&hAlg, algid,
NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG);
if(status >
0) {
fprintf(stderr,
"Error: dav_pw2key: BCryptOpenAlgorithmProvider failed: 0x%X\n", (
unsigned int)status);
return NULL;
}
status = BCryptDeriveKeyPBKDF2(
hAlg,
(
PUCHAR)password,
len,
(
PUCHAR)salt,
saltlen,
DAV_CRYPTO_ITERATION_COUNT,
keydata,
128,
0);
BCryptCloseAlgorithmProvider(hAlg,
0);
if(status) {
fprintf(stderr,
"Error: dav_pw2key: BCryptDeriveKeyPBKDF2 failed: 0x%X\n", (
unsigned int)status);
return NULL;
}
DavKey *key = malloc(
sizeof(DavKey));
key->data = malloc(keylen);
key->length = keylen;
key->name =
NULL;
key->type = enc;
memcpy(key->data, keydata, keylen);
return key;
}
#endif
CxBuffer* aes_encrypt_buffer(CxBuffer *in, DavKey *key) {
CxBuffer *encbuf = cxBufferCreate(
NULL, in->size, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
if(!encbuf) {
return NULL;
}
AESEncrypter *enc = aes_encrypter_new(
key,
in,
(dav_read_func)cxBufferRead,
NULL);
if(!enc) {
cxBufferFree(encbuf);
return NULL;
}
char buf[
1024];
size_t r;
while((r = aes_read(buf,
1,
1024, enc)) >
0) {
cxBufferWrite(buf,
1, r, encbuf);
}
aes_encrypter_close(enc);
encbuf->pos =
0;
return encbuf;
}
CxBuffer* aes_decrypt_buffer(CxBuffer *in, DavKey *key) {
CxBuffer *decbuf = cxBufferCreate(
NULL, in->size, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
if(!decbuf) {
return NULL;
}
AESDecrypter *dec = aes_decrypter_new(
key,
decbuf,
(dav_write_func)cxBufferWrite);
if(!dec) {
cxBufferFree(decbuf);
return NULL;
}
aes_write(in->space,
1, in->size, dec);
aes_decrypter_shutdown(dec);
aes_decrypter_close(dec);
decbuf->pos =
0;
return decbuf;
}