# HG changeset patch # User Olaf Wintermann # Date 1537005396 -7200 # Node ID 6bf798ad3aec4a0f4cef12a6ec80d27f3f425cf9 # Parent 6ab1f4ad2835629903140080a40991a0776a3e56 adds encrypted password store new repo config element: new dav command: add-user diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/Makefile --- a/dav/Makefile Thu Sep 06 12:51:37 2018 +0200 +++ b/dav/Makefile Sat Sep 15 11:56:36 2018 +0200 @@ -37,8 +37,9 @@ DAV_SRC += assistant.c DAV_SRC += tar.c DAV_SRC += system.c +DAV_SRC += pwd.c -SYNC_SRC = sync.c +SYNC_SRC = sync.c SYNC_SRC += config.c SYNC_SRC += scfg.c SYNC_SRC += sopt.c @@ -48,6 +49,7 @@ SYNC_SRC += libxattr.c SYNC_SRC += tags.c SYNC_SRC += system.c +SYNC_SRC += pwd.c DAV_OBJ = $(DAV_SRC:%.c=../build/tool/%$(OBJ_EXT)) SYNC_OBJ = $(SYNC_SRC:%.c=../build/tool/%$(OBJ_EXT)) diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/config.c --- a/dav/config.c Thu Sep 06 12:51:37 2018 +0200 +++ b/dav/config.c Sat Sep 15 11:56:36 2018 +0200 @@ -34,6 +34,7 @@ #include #include +#include "pwd.h" #include "config.h" #include "main.h" #include @@ -62,6 +63,8 @@ static UcxMap *repos; static UcxMap *keys; +static PwdStore *pstore; + int check_config_dir(void) { char *file = util_concat_path(ENV_HOME, ".dav"); int ret = 0; @@ -100,6 +103,10 @@ repos = ucx_map_new(16); keys = ucx_map_new(16); + char *pwfile = util_concat_path(ENV_HOME, ".dav/pw.crypt"); + pstore = pwdstore_open(pwfile); + free(pwfile); + char *file = util_concat_path(ENV_HOME, ".dav/config.xml"); struct stat s; @@ -216,6 +223,8 @@ repo->user = strdup(value); } else if(xstreq(key, "password")) { repo->password = util_base64decode(value); + } else if(xstreq(key, "stored-user")) { + repo->stored_user = strdup(value); } else if(xstreq(key, "default-key")) { repo->default_key = strdup(value); } else if(xstreq(key, "full-encryption")) { @@ -751,3 +760,14 @@ } return list; } + +PwdStore* get_pwdstore(void) { + return pstore; +} + +int pwdstore_save(PwdStore *pwdstore) { + char *pwfile = util_concat_path(ENV_HOME, ".dav/pw.crypt"); + int ret = pwdstore_store(pwdstore, pwfile); + free(pwfile); + return ret; +} diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/config.h --- a/dav/config.h Thu Sep 06 12:51:37 2018 +0200 +++ b/dav/config.h Sat Sep 15 11:56:36 2018 +0200 @@ -32,6 +32,7 @@ #include #include #include +#include "pwd.h" #ifdef __cplusplus extern "C" { @@ -56,6 +57,7 @@ char *url; char *user; char *password; + char *stored_user; char *default_key; char *cert; bool verification; @@ -91,6 +93,9 @@ int list_repositories(void); UcxList* get_repositories(void); +PwdStore* get_pwdstore(void); +int pwdstore_save(PwdStore *pwdstore); + #ifdef __cplusplus } #endif diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/main.c --- a/dav/main.c Thu Sep 06 12:51:37 2018 +0200 +++ b/dav/main.c Sat Sep 15 11:56:36 2018 +0200 @@ -46,6 +46,7 @@ #include "error.h" #include "assistant.h" #include "system.h" +#include "pwd.h" #include "main.h" static DavContext *ctx; @@ -152,6 +153,8 @@ } else if(!strcasecmp(cmd, "repository-url") || !strcasecmp(cmd, "repo-url")) { ret = cmd_repository_url(args); + } else if(!strcasecmp(cmd, "add-user")) { + ret = cmd_add_user(args); } else if(!strcasecmp(cmd, "version") || !strcasecmp(cmd, "-version") || !strcasecmp(cmd, "--version")) { fprintf(stderr, "dav %s\n", DAV_VERSION); @@ -402,7 +405,35 @@ } static DavSession* connect_to_repo(Repository *repo, CmdArgs *a) { - DavSession *sn = dav_session_new_auth(ctx, repo->url, repo->user, repo->password); + char *user = repo->user; + char *password = repo->password; + if(repo->stored_user) { + PwdStore *pstore = get_pwdstore(); + if(pstore) { + char *ps_password = util_password_input("Unlock password store: "); + if(ps_password) { + if(!pwdstore_setpassword(pstore, ps_password)) { + if(!pwdstore_decrypt(pstore)) { + PwdEntry *stored_user = pwdstore_get(pstore, repo->stored_user); + if(stored_user) { + user = stored_user->user; + password = stored_user->password; + } else { + fprintf(stderr, "Error: stored user '%s' not found\n", repo->stored_user); + } + } else { + fprintf(stderr, "Error: cannot decrypt password store\n"); + } + } else { + fprintf(stderr, "Error: cannot create key from password\n"); + } + } + } else { + fprintf(stderr, "Error: no password store available\n"); + } + } + + DavSession *sn = dav_session_new_auth(ctx, repo->url, user, password); sn->flags = get_repository_flags(repo); sn->key = dav_context_get_key(ctx, repo->default_key); curl_easy_setopt(sn->handle, CURLOPT_HTTPAUTH, repo->authmethods); @@ -2031,6 +2062,32 @@ } } +int cmd_add_user(CmdArgs *args) { + char *user = assistant_getcfg("User"); + char *password = util_password_input("Password: "); + if(user && password) { + PwdStore *pstore = get_pwdstore(); + if(!pstore) { + pstore = pwdstore_new(); + } + pwdstore_put(pstore, user, password); + char *master_pw = util_password_input("Master password: "); + if(!master_pw) { + return 1; + } + if(pwdstore_setpassword(pstore, master_pw)) { + fprintf(stderr, "Error: Cannot generate key from password.\nAbort.\n"); + return 1; + } + int ret = pwdstore_save(pstore); + if(ret) { + fprintf(stderr, "Error: saving password store failed.\n"); + } + return ret; + } + return 1; +} + int shell_completion(CmdArgs *args, int index) { if(args->argc < 2 || args->argc < 3) { diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/main.h --- a/dav/main.h Thu Sep 06 12:51:37 2018 +0200 +++ b/dav/main.h Sat Sep 15 11:56:36 2018 +0200 @@ -60,7 +60,6 @@ typedef int(*getfunc)(Repository *, GetResource *, CmdArgs *, void *); void print_usage(char *cmd); -char* password_input(char *prompt); int request_auth(Repository *repo, DavSession *sn, CmdArgs *args); int update_progress(DavResource *res, int64_t total, int64_t now, Progress *p); @@ -104,6 +103,8 @@ int cmd_repository_url(CmdArgs *args); +int cmd_add_user(CmdArgs *args); + int shell_completion(CmdArgs *args, int index); int url_completion(char *url); diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/pwd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/pwd.c Sat Sep 15 11:56:36 2018 +0200 @@ -0,0 +1,233 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include + +#include "pwd.h" + +#include +#include + + + +PwdStore* pwdstore_open(const char *file) { + FILE *in = fopen(file, "r"); + if(!in) { + return NULL; + } + + UcxBuffer *buf = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); + ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write); + fclose(in); + + if(buf->size < PWDS_HEADER_SIZE || buf->space[0] != PWDS_MAGIC_CHAR) { + ucx_buffer_free(buf); + return NULL; + } + + PwdStore *p = malloc(sizeof(PwdStore)); + p->pwds = ucx_map_new(16); + p->content = buf; + p->key = NULL; + p->isdecrypted = 0; + + return p; +} + +PwdStore* pwdstore_new(void) { + PwdStore *p = calloc(1, sizeof(PwdStore)); + p->pwds = ucx_map_new(16); + p->content = ucx_buffer_new(NULL, PWDS_HEADER_SIZE, UCX_BUFFER_AUTOEXTEND); + PWDS_MAGIC(p) = PWDS_MAGIC_CHAR; + PWDS_VERSION(p) = 1; + PWDS_ENC(p) = DAV_KEY_AES256; + PWDS_PWFUNC(p) = DAV_PWFUNC_PBKDF2_SHA256; + dav_rand_bytes(p->content->space+4, 16); + return p; +} + +static int read_pwdentry(PwdStore *p, UcxBuffer *in) { + int type = ucx_buffer_getc(in); + if(type == EOF || type != 0) { + // only type 0 supported yet + return 0; + } + + uint32_t ulen = 0; + uint32_t plen = 0; + + if(ucx_buffer_read(&ulen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { + return 0; + } + ulen = ntohl(ulen); + if(ulen == 0 || ulen > PWDSTORE_MAX_LEN) { + return 0; + } + + char *user = malloc(ulen+1); + user[ulen] = 0; + if(ucx_buffer_read(user, 1, ulen, in) != ulen) { + free(user); + return 0; + } + + if(ucx_buffer_read(&plen, 1, sizeof(uint32_t), in) != sizeof(uint32_t)) { + return 0; + } + plen = ntohl(plen); + if(plen == 0 || plen > PWDSTORE_MAX_LEN) { + return 0; + } + char *password = malloc(plen+1); + password[plen] = 0; + if(ucx_buffer_read(password, 1, plen, in) != plen) { + free(user); + free(password); + return 0; + } + + pwdstore_put(p, user, password); + free(user); + free(password); + return 1; + +} + +int pwdstore_decrypt(PwdStore *p) { + if(!p->key) { + return 1; + } + + // decrypt contet + size_t encsz = p->content->size - PWDS_HEADER_SIZE; + UcxBuffer *enc = ucx_buffer_new(p->content->space + PWDS_HEADER_SIZE, encsz, 0); + enc->size = encsz; + enc->size = p->content->size - PWDS_HEADER_SIZE; + UcxBuffer *content = aes_decrypt_buffer(enc, p->key); + ucx_buffer_free(enc); + if(!content) { + return 1; + } + + while(read_pwdentry(p, content)) {} + + ucx_buffer_free(content); + + return 0; +} + +int pwdstore_setpassword(PwdStore *p, const char *password) { + DavKey *key = dav_pw2key( + password, + p->content->space + 4, + 16, + PWDS_PWFUNC(p), + PWDS_ENC(p)); + if(!key) { + return 1; + } + + p->key = key; + return 0; +} + +void pwdstore_encsettings(PwdStore *p, uint8_t enc, uint8_t pwfunc) { + PWDS_ENC(p) = enc; + PWDS_PWFUNC(p) = pwfunc; +} + +static void free_entry(PwdEntry *e) { + free(e->user); + free(e->password); + free(e); +} + +void pwdstore_free(PwdStore* p) { + ucx_map_free_content(p->pwds, (ucx_destructor)free_entry); + ucx_map_free(p->pwds); + + if(p->content) { + ucx_buffer_free(p->content); + } + + free(p); +} + +PwdEntry* pwdstore_get(PwdStore *p, const char *username) { + return ucx_map_cstr_get(p->pwds, username); +} + +void pwdstore_put(PwdStore *p, const char *username, const char *password) { + PwdEntry *entry = malloc(sizeof(PwdEntry)); + entry->user = strdup(username); + entry->password = strdup(password); + ucx_map_cstr_put(p->pwds, entry->user, entry); +} + +int pwdstore_store(PwdStore *p, const char *file) { + if(!p->key) { + return 1; + } + + UcxBuffer *content = ucx_buffer_new(NULL, 2048, UCX_BUFFER_AUTOEXTEND); + + UcxMapIterator i = ucx_map_iterator(p->pwds); + PwdEntry *value; + UCX_MAP_FOREACH(key, value, i) { + ucx_buffer_putc(content, 0); // type + uint32_t ulen = strlen(value->user); + uint32_t plen = strlen(value->password); + uint32_t netulen = htonl(ulen); + uint32_t netplen = htonl(plen); + ucx_buffer_write(&netulen, 1, sizeof(uint32_t), content); + ucx_buffer_write(value->user, 1, ulen, content); + ucx_buffer_write(&netplen, 1, sizeof(uint32_t), content); + ucx_buffer_write(value->password, 1, plen, content); + } + + content->pos = 0; + UcxBuffer *enc = aes_encrypt_buffer(content, p->key); + + p->content->pos = PWDS_HEADER_SIZE; + p->content->size = PWDS_HEADER_SIZE; + ucx_buffer_write(enc->space, 1, enc->size, p->content); + + ucx_buffer_free(enc); + + FILE *out = fopen(file, "w"); + if(!out) { + return 1; + } + fwrite(p->content->space, 1, p->content->size, out); + fclose(out); + + return 0; +} diff -r 6ab1f4ad2835 -r 6bf798ad3aec dav/pwd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/pwd.h Sat Sep 15 11:56:36 2018 +0200 @@ -0,0 +1,138 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2018 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PWD_H +#define PWD_H + +#include +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PWDSTORE_MAX_LEN 1024 + +/* + * File Format: + * + * file = header, enc_content + * header = magic, version, enc, pwfunc, salt + * magic = 1 byte + * version = 1 byte + * enc = 1 byte + * pwfunc = 1 byte + * salt = 16 bytes + * content = { entry } + * entry = length username length password + * length = uint16 + * username = string + * password = string + * + * The content is AES encrypted with a key derived from a password + * and the salt. The first 16 bytes are the aes iv. + * + * All integers are big endian + */ + +#define PWDS_HEADER_SIZE 20 + +typedef struct PwdStore PwdStore; +typedef struct PwdEntry PwdEntry; + +struct PwdStore { + /* + * map of all usernames and passwords + * key is the username + * value is PwdEntry* + */ + UcxMap *pwds; + + /* + * a buffer containing the complete file content + */ + UcxBuffer *content; + + /* + * key used for encryption/decryption + */ + DavKey *key; + + /* + * indicates if the PwdStore is decrypted with pwdstore_decrypt + */ + uint8_t isdecrypted; +}; + +#define PWDS_MAGIC(p) (p)->content->space[0] +#define PWDS_VERSION(p) (p)->content->space[1] +#define PWDS_ENC(p) (p)->content->space[2] +#define PWDS_PWFUNC(p) (p)->content->space[3] + +#define PWDS_MAGIC_CHAR 'P' + +struct PwdEntry { + char *user; + char *password; +}; + +/* + * opens the password store + * the content is still encrypted and must be decrypted using pwdstore_decrypt + */ +PwdStore* pwdstore_open(const char *file); + +PwdStore* pwdstore_new(void); + +/* + * decrypts the password store with a password + */ +int pwdstore_decrypt(PwdStore *p); + +int pwdstore_setpassword(PwdStore *p, const char *password); + +void pwdstore_encsettings(PwdStore *p, uint8_t enc, uint8_t pwfunc); + +void pwdstore_free(PwdStore* p); + +PwdEntry* pwdstore_get(PwdStore *p, const char *username); + +void pwdstore_put(PwdStore *p, const char *username, const char *password); + +int pwdstore_store(PwdStore *p, const char *file); + +#ifdef __cplusplus +} +#endif + +#endif /* PWD_H */ + diff -r 6ab1f4ad2835 -r 6bf798ad3aec libidav/crypto.c --- a/libidav/crypto.c Thu Sep 06 12:51:37 2018 +0200 +++ b/libidav/crypto.c Sat Sep 15 11:56:36 2018 +0200 @@ -56,6 +56,10 @@ #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); @@ -112,8 +116,8 @@ int outlen = len + 16; unsigned char *out = malloc(outlen); - EVP_DecryptUpdate(dec->ctx, out, &len, buf, len); - ssize_t wlen = dec->write(out, 1, len, dec->stream); + 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; @@ -344,6 +348,63 @@ return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH); } +DavKey* dav_pw2key(const char *password, const char *salt, int saltlen, int pwfunc, int enc) { + if(!password) { + return NULL; + } + size_t len = strlen(password); + if(len == 0) { + return NULL; + } + + // setup key data and length + 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; + } + + // generate key + 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; + } + + // create DavKey with generated data + 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 @@ -697,3 +758,46 @@ } #endif + +UcxBuffer* aes_encrypt_buffer(UcxBuffer *in, DavKey *key) { + UcxBuffer *encbuf = ucx_buffer_new( + NULL, + in->size+16, + UCX_BUFFER_AUTOEXTEND); + + AESEncrypter *enc = aes_encrypter_new( + key, + in, + (dav_read_func)ucx_buffer_read); + if(!enc) { + ucx_buffer_free(encbuf); + return NULL; + } + + char buf[1024]; + size_t r; + while((r = aes_read(buf, 1, 1024, enc)) > 0) { + ucx_buffer_write(buf, 1, r, encbuf); + } + aes_encrypter_close(enc); + + encbuf->pos = 0; + return encbuf; +} + +UcxBuffer* aes_decrypt_buffer(UcxBuffer *in, DavKey *key) { + UcxBuffer *decbuf = ucx_buffer_new( + NULL, + in->size, + UCX_BUFFER_AUTOEXTEND); + AESDecrypter *dec = aes_decrypter_new( + key, + decbuf, + (dav_write_func)ucx_buffer_write); + + aes_write(in->space, 1, in->size, dec); + aes_decrypter_shutdown(dec); + aes_decrypter_close(dec); + decbuf->pos = 0; + return decbuf; +} diff -r 6ab1f4ad2835 -r 6bf798ad3aec libidav/crypto.h --- a/libidav/crypto.h Thu Sep 06 12:51:37 2018 +0200 +++ b/libidav/crypto.h Sat Sep 15 11:56:36 2018 +0200 @@ -67,6 +67,11 @@ extern "C" { #endif +#define DAV_PWFUNC_PBKDF2_SHA256 0 +#define DAV_PWFUNC_PBKDF2_SHA512 1 + +#define DAV_CRYPTO_ITERATION_COUNT 4000 + typedef struct { DAV_AES_CTX ctx; DAV_SHA_CTX sha256; @@ -109,6 +114,11 @@ char* dav_create_hash(const char *data, size_t len); +DavKey* dav_pw2key(const char *password, const char *salt, int saltlen, int pwfunc, int enc); + +UcxBuffer* aes_encrypt_buffer(UcxBuffer *buf, DavKey *key); +UcxBuffer* aes_decrypt_buffer(UcxBuffer *buf, DavKey *key); + #ifdef __cplusplus } #endif diff -r 6ab1f4ad2835 -r 6bf798ad3aec test/crypto.c --- a/test/crypto.c Thu Sep 06 12:51:37 2018 +0200 +++ b/test/crypto.c Sat Sep 15 11:56:36 2018 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2017 Olaf Wintermann. All rights reserved. + * Copyright 2018 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: @@ -247,6 +247,34 @@ UCX_TEST_END; } +UCX_TEST(test_crypto_buffer) { + UCX_TEST_BEGIN; + + for(int i=0;i<32;i++) { + DavKey *key = i < 16 ? &keys256[i] : &keys128[i%16]; + + for(int j=0;j<20;j++) { + UcxBuffer *content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); + ucx_buffer_puts(content, strings[j]); + content->pos = 0; + + UcxBuffer *enc = aes_encrypt_buffer(content, key); + UCX_TEST_ASSERT(enc->size >= content->size + 16, "aes_encrypt_buffer failed"); + + UcxBuffer *dec = aes_decrypt_buffer(enc, key); + UCX_TEST_ASSERT(dec->size == content->size, "aes_decrypt_buffer failed"); + + UCX_TEST_ASSERT(!memcmp(content->space, dec->space, dec->size), "decrypted buffer has wrong content"); + + ucx_buffer_free(content); + ucx_buffer_free(enc); + ucx_buffer_free(dec); + } + } + + UCX_TEST_END; +} + UCX_TEST(test_crypto_stream) { UcxBuffer *data = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); UcxBuffer *cbuf = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); @@ -283,6 +311,13 @@ UCX_TEST_ASSERT(slen == pbuf->pos, "wrong length after enc-dec"); UCX_TEST_ASSERT(!memcmp(strings[j], pbuf->space, slen), "wrong content after enc-dec"); + + data->pos = 0; + UcxBuffer *enc2 = aes_encrypt_buffer(data, key); + UcxBuffer *dec2 = aes_decrypt_buffer(enc2, key); + + UCX_TEST_ASSERT(dec2->size == data->size, "dec2 has wrong size"); + UCX_TEST_ASSERT(!memcmp(strings[j], dec2->space, dec2->size), "dec2 has wrong content"); } } diff -r 6ab1f4ad2835 -r 6bf798ad3aec test/crypto.h --- a/test/crypto.h Thu Sep 06 12:51:37 2018 +0200 +++ b/test/crypto.h Sat Sep 15 11:56:36 2018 +0200 @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright 2017 Olaf Wintermann. All rights reserved. + * Copyright 2018 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: @@ -37,7 +37,7 @@ UCX_TEST(test_util_decrypt_str_k); UCX_TEST(test_util_encrypt_str_k); - +UCX_TEST(test_crypto_buffer); UCX_TEST(test_crypto_stream); diff -r 6ab1f4ad2835 -r 6bf798ad3aec test/main.c --- a/test/main.c Thu Sep 06 12:51:37 2018 +0200 +++ b/test/main.c Sat Sep 15 11:56:36 2018 +0200 @@ -45,6 +45,7 @@ ucx_test_register(suite, test_util_base64encode); ucx_test_register(suite, test_util_decrypt_str_k); ucx_test_register(suite, test_util_encrypt_str_k); + ucx_test_register(suite, test_crypto_buffer); ucx_test_register(suite, test_crypto_stream); ucx_test_run(suite, stdout);