diff --git a/Makefile b/Makefile
index 0edb03a..92cc500 100644
--- a/Makefile
+++ b/Makefile
@@ -406,7 +406,8 @@ install: all
 PHONY += run-tests
 tests: \
 	acceptance-tests \
-	suricatta-tests
+	suricatta-tests \
+	corelib-tests
 
 PHONY += acceptance-tests
 acceptance-tests: FORCE
@@ -416,6 +417,10 @@ PHONY += suricatta-tests
 suricatta-tests: FORCE
 	$(Q)$(MAKE) $(build)=suricatta/test SWOBJS="$(swupdate-objs)" SWLIBS="$(swupdate-libs)" LDLIBS="$(LDLIBS)" tests
 
+PHONY += corelib-tests
+corelib-tests: FORCE
+	$(Q)$(MAKE) $(build)=corelib/test SWOBJS="$(swupdate-objs)" SWLIBS="$(swupdate-libs)" LDLIBS="$(LDLIBS)" tests
+
 # The actual objects are generated when descending,
 # make sure no implicit rule kicks in
 $(sort $(swupdate-all)): $(swupdate-dirs) ;
diff --git a/corelib/test/Makefile b/corelib/test/Makefile
new file mode 100644
index 0000000..b071177
--- /dev/null
+++ b/corelib/test/Makefile
@@ -0,0 +1,64 @@
+## Author: Christian Storm
+## Copyright (C) 2017, Siemens AG
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License as
+## published by the Free Software Foundation; either version 2 of
+## the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc.
+
+tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt
+
+ccflags-y += -I$(src)/../
+
+TARGETS    = $(addprefix $(obj)/, $(tests-y))
+tests-objs = $(addsuffix .o,   $(TARGETS))
+tests-lnk  = $(addsuffix .lnk, $(TARGETS))
+targets   += $(addsuffix .o,   $(tests-y))
+
+ifneq ($(CONFIG_EXTRA_LDFLAGS),)
+EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS)))#"))
+endif
+
+## transfer __mock_*() functions to according linker flags via rudimentary regex awk parsing
+LDMOCKS = `/usr/bin/awk '/^[^(extern)|(static)]*([\*_[:alnum:]]+[[:blank:]]+)+[\*]*__wrap_/{where = match($$0,"__wrap_[_[:alnum:]]+"); if (RSTART > 0) { print "-Wl,--wrap=" substr($$0, RSTART+7, RLENGTH-7);}}' $(basename $@).c`
+
+quiet_cmd_linktestexe = LD      $(basename $@)
+      cmd_linktestexe = $(srctree)/scripts/trylink \
+						"$(basename $@)" \
+						"$(CC)" \
+						"$(KBUILD_CFLAGS)" \
+						"$(LDFLAGS) $(EXTRA_LDFLAGS) $(LDMOCKS)" \
+						"$(basename $@).o $(subst core/built-in.o,core/built-in.o.tmp,$(SWOBJS))" \
+						"$(SWLIBS)" \
+						"$(LDLIBS) cmocka"
+
+EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; CMOCKA_MESSAGE_OUTPUT=TAP $(var)
+
+PHONY += default
+default:
+	$(info please run 'make corelib-tests' in swupdate main directory)
+
+PHONY += tests
+ifneq "$(tests-y)" ""
+tests: $(tests-objs) $(tests-lnk)
+	@+$(foreach var,$(TARGETS),$(EXECUTE_TEST);)
+else
+tests:
+	@$(info crypto functions are disabled, nothing to test.)
+	@:
+endif
+
+$(obj)/%.lnk: $(objtree)/core/built-in.o
+	$(Q)strip -N main -o $(objtree)/core/built-in.o.tmp $(objtree)/core/built-in.o
+	$(Q)$(call cmd,linktestexe)
+
+.PHONY: $(PHONY)
diff --git a/corelib/test/test_crypt.c b/corelib/test/test_crypt.c
new file mode 100644
index 0000000..84ac6ed
--- /dev/null
+++ b/corelib/test/test_crypt.c
@@ -0,0 +1,148 @@
+/*
+ * Author: Christian Storm
+ * Copyright (C) 2017, Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <util.h>
+#include <sslapi.h>
+
+struct cryptdata {
+	unsigned char *key;
+	unsigned char *iv;
+	unsigned char *salt;
+	unsigned char *crypttext;
+};
+
+static void hex2bin(unsigned char *dest, const unsigned char *source)
+{
+	unsigned int val;
+	for (unsigned int i = 0; i < strlen((const char *)source); i += 2) {
+		val = from_ascii((const char *)&source[i], 2, LG_16);
+		dest[i / 2] = val;
+	}
+}
+
+static void do_crypt(struct cryptdata *crypt, unsigned char *CRYPTTEXT, unsigned char *PLAINTEXT)
+{
+	int len;
+	void *dcrypt = swupdate_DECRYPT_init(crypt->key, crypt->iv, crypt->salt);
+	assert_non_null(dcrypt);
+
+	unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH);
+	int ret = swupdate_DECRYPT_update(dcrypt, buffer, &len, crypt->crypttext, strlen((const char *)CRYPTTEXT) / 2);
+	assert_true(ret >= 0);
+	assert_true(len == 0);
+
+	ret = swupdate_DECRYPT_final(dcrypt, crypt->crypttext, &len);
+	assert_true(ret == 0);
+	assert_true(len == (int)strlen((const char *)PLAINTEXT));
+	assert_true(strncmp((const char *)buffer, (const char *)PLAINTEXT, len) == 0);
+	free(buffer);
+}
+
+static void test_crypt_nosalt(void **state)
+{
+	(void)state;
+
+	unsigned char KEY[] = "E5E9FA1BA31ECD1AE84F75CAAA474F3A663F05F412028F81DA65D26EE56424B2";
+	unsigned char IV[] = "E93DA465B309C53FEC5FF93C9637DA58";
+	unsigned char CRYPTTEXT[] = "E4B7745CA14039555CECD548BB33E0C3";
+	unsigned char PLAINTEXT[] = "CRYPTTEST";
+
+	struct cryptdata crypt;
+	hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
+	hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
+	crypt.salt = NULL;
+	hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+
+	do_crypt(&crypt, &CRYPTTEXT[0], &PLAINTEXT[0]);
+
+	free(crypt.key);
+	free(crypt.iv);
+	free(crypt.crypttext);
+}
+
+static void test_crypt_salt(void **state)
+{
+	(void)state;
+
+	unsigned char KEY[] = "69D54287F856D30B51B812FDF714556778CF31E1B104D9C68BD90C669C37D1AB";
+	unsigned char IV[] = "E7039ABFCA63EB8EB1D320F7918275B2";
+	unsigned char SALT[] = "F75A9C11F7F63C08";
+	unsigned char CRYPTTEXT[] = "A17EBBB1A28459352FE3A994404E35AA";
+	unsigned char PLAINTEXT[] = "CRYPTTEST";
+
+	struct cryptdata crypt;
+	hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
+	hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
+	hex2bin((crypt.salt = calloc(1, strlen((const char *)SALT))), SALT);
+	hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+
+	do_crypt(&crypt, &CRYPTTEXT[0], &PLAINTEXT[0]);
+
+	free(crypt.key);
+	free(crypt.iv);
+	free(crypt.salt);
+	free(crypt.crypttext);
+}
+
+static void test_crypt_failure(void **state)
+{
+	(void)state;
+
+	unsigned char KEY[] = "E5E9FA1BA31ECD1AE84F75CAAA474F3A663F05F412028F81DA65D26EE56424B2";
+	unsigned char IV[] = "E93DA465B309C53FEC5FF93C9637DA58";
+	unsigned char CRYPTTEXT[] = "CAFECAFECAFECAFECAFECAFECAFECAFE";
+
+	struct cryptdata crypt;
+	hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
+	hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
+	crypt.salt = NULL;
+	hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+
+	int len;
+	void *dcrypt = swupdate_DECRYPT_init(crypt.key, crypt.iv, crypt.salt);
+	assert_non_null(dcrypt);
+
+	unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH);
+	int ret = swupdate_DECRYPT_update(dcrypt, buffer, &len, crypt.crypttext, strlen((const char *)CRYPTTEXT) / 2);
+	ret = swupdate_DECRYPT_final(dcrypt, crypt.crypttext, &len);
+	assert_true(ret != 0);
+	free(buffer);
+
+	free(crypt.key);
+	free(crypt.iv);
+	free(crypt.salt);
+	free(crypt.crypttext);
+}
+
+int main(void)
+{
+	int error_count = 0;
+	const struct CMUnitTest crypt_tests[] = {
+		cmocka_unit_test(test_crypt_nosalt),
+		cmocka_unit_test(test_crypt_failure),
+		cmocka_unit_test(test_crypt_salt)
+	};
+	error_count += cmocka_run_group_tests_name("crypt", crypt_tests, NULL, NULL);
+	return error_count;
+}
