Unit and system tests for YACA 84/229084/38
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Thu, 2 Apr 2020 15:41:05 +0000 (17:41 +0200)
committerLukasz Pawelczyk <l.pawelczyk@samsung.com>
Fri, 26 Jun 2020 15:38:58 +0000 (17:38 +0200)
Tests that aim to thoroughly test and cover YACA's code. Whole
functionality, most combinations of correct and incorrect parameters.

Those tests cover >80% of the code, leaving only error handlers from
OpenSSL errors.

Change-Id: Ieb29f7adaf1edeb30f653c43fb46a2324bdcb040

14 files changed:
CMakeLists.txt
packaging/yaca.spec
tests/CMakeLists.txt [new file with mode: 0644]
tests/common.cpp [new file with mode: 0644]
tests/common.h [new file with mode: 0644]
tests/test_crypto.cpp [new file with mode: 0644]
tests/test_debug.cpp [new file with mode: 0644]
tests/test_digest.cpp [new file with mode: 0644]
tests/test_encrypt.cpp [new file with mode: 0644]
tests/test_key.cpp [new file with mode: 0644]
tests/test_rsa.cpp [new file with mode: 0644]
tests/test_seal.cpp [new file with mode: 0644]
tests/test_sign.cpp [new file with mode: 0644]
tests/test_simple.cpp [new file with mode: 0644]

index ec14e13..2c1a1f4 100644 (file)
@@ -55,6 +55,7 @@ MESSAGE(STATUS "-------------------------------------------------")
 SET(CMAKE_C_FLAGS_DEBUG        "-std=c11 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
 SET(CMAKE_C_FLAGS_RELEASE      "-std=c11 -O2 -DNDEBUG")
 SET(CMAKE_C_FLAGS_COVERAGE     "-std=c11 -O0 -ggdb --coverage -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_CXX_FLAGS_COVERAGE   "-std=c++14 -O0 -ggdb --coverage -Wp,-U_FORTIFY_SOURCE")
 
 ADD_DEFINITIONS("-fPIC")   # Position Independent Code
 ADD_DEFINITIONS("-Werror") # Make all warnings into errors
@@ -75,6 +76,7 @@ ENDIF()
 SET(API_FOLDER ${PROJECT_SOURCE_DIR}/api/yaca)
 SET(EXAMPLES_FOLDER ${PROJECT_SOURCE_DIR}/examples)
 SET(SRC_FOLDER ${PROJECT_SOURCE_DIR}/src)
+SET(TESTS_FOLDER ${PROJECT_SOURCE_DIR}/tests)
 SET(PYTHON_FOLDER ${PROJECT_SOURCE_DIR}/python)
 
 IF(NOT DEFINED LIB_INSTALL_DIR)
@@ -101,6 +103,7 @@ CONFIGURE_FILE(packaging/yaca.manifest.in yaca.manifest @ONLY)
 
 ADD_SUBDIRECTORY(${SRC_FOLDER})
 ADD_SUBDIRECTORY(${EXAMPLES_FOLDER})
+ADD_SUBDIRECTORY(${TESTS_FOLDER})
 IF(NOT WITHOUT_PYTHON)
        ADD_SUBDIRECTORY(${PYTHON_FOLDER})
 ENDIF(NOT WITHOUT_PYTHON)
index 4f9cd02..7802567 100644 (file)
@@ -11,6 +11,7 @@ BuildRequires:      cmake
 BuildRequires:      python3 >= 3.4
 BuildRequires:      pkgconfig(capi-base-common)
 BuildRequires:      pkgconfig(openssl1.1)
+BuildRequires:      boost-devel
 %if %{build_type} == "COVERAGE"
 BuildRequires:      lcov
 %endif
@@ -83,6 +84,18 @@ The package provides Yet Another Crypto API example files.
 %{_bindir}/yaca-example*
 %{_datadir}/%{name}/examples
 
+## Tests Package ############################################################
+%package tests
+Summary:        Yet Another Crypto API tests
+Group:          Security/Other
+Requires:       yaca = %{version}-%{release}
+
+%description tests
+The package provides Yet Another Crypto API unit tests.
+
+%files tests
+%{_bindir}/yaca-unit-tests*
+
 ## Python3 Package ############################################################
 %package -n python3-yaca
 Summary:        Yet Another Crypto API Python3 bindings
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4ebee1a
--- /dev/null
@@ -0,0 +1,58 @@
+#
+#  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#  Contact: Krzysztof Jackiewicz <k.jackiewicz@samsung.com>
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License
+#
+#
+# @file   CMakeLists.txt
+# @author Lukasz Pawelczyk (l.pawelczyk@samsung.com)
+#
+
+SET(TESTS_NAME yaca-unit-tests)
+FILE(GLOB YACA_SOURCES ${SRC_FOLDER}/*.c)
+SET(TESTS_SOURCES
+       common.cpp
+       test_debug.cpp
+       test_crypto.cpp
+       test_key.cpp
+       test_simple.cpp
+       test_rsa.cpp
+       test_digest.cpp
+       test_encrypt.cpp
+       test_seal.cpp
+       test_sign.cpp
+       )
+
+FIND_PACKAGE(Boost REQUIRED unit_test_framework)
+ADD_DEFINITIONS("-DBOOST_TEST_DYN_LINK")
+
+INCLUDE_DIRECTORIES(${API_FOLDER} ${SRC_FOLDER})
+INCLUDE_DIRECTORIES(SYSTEM ${YACA_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
+
+ADD_EXECUTABLE(${TESTS_NAME} ${YACA_SOURCES} ${TESTS_SOURCES})
+TARGET_LINK_LIBRARIES(${TESTS_NAME}
+                                         ${YACA_DEPS_LIBRARIES}
+                                         ${CMAKE_THREAD_LIBS_INIT}
+                                         ${Boost_LIBRARIES})
+
+INSTALL(TARGETS                 ${TESTS_NAME}
+               DESTINATION      ${BIN_INSTALL_DIR}
+               PERMISSIONS      OWNER_READ
+                                        OWNER_WRITE
+                                        OWNER_EXECUTE
+                                        GROUP_READ
+                                        GROUP_EXECUTE
+                                        WORLD_READ
+                                        WORLD_EXECUTE)
diff --git a/tests/common.cpp b/tests/common.cpp
new file mode 100644 (file)
index 0000000..e7b5db3
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    common.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Common code for YACA unit tests
+ */
+
+#define BOOST_TEST_MODULE YacaUnitTests
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/unit_test_log.hpp>
+#include <boost/test/results_reporter.hpp>
+#include <iostream>
+
+#include <yaca_crypto.h>
+#include <yaca_error.h>
+#include <yaca_key.h>
+#include <yaca_encrypt.h>
+#include "../src/debug.h"
+
+#include "common.h"
+
+
+namespace {
+
+size_t error_cb_called = 0;
+
+void debug_error_cb(const char *buf)
+{
+       std::cout << buf;
+       ++error_cb_called;
+}
+
+} // namespace
+
+
+DebugFixture::DebugFixture()
+{
+       error_cb_called = 0;
+       yaca_debug_set_error_cb(&debug_error_cb);
+}
+
+DebugFixture::~DebugFixture()
+{
+       /* No ERROR_DUMP should've been called. If there is one that is
+        * harmless (that happens) it should be added to error_handle
+        * anyway.
+        */
+       BOOST_REQUIRE(error_cb_called == 0);
+       yaca_debug_set_error_cb(NULL);
+}
+
+InitFixture::InitFixture()
+{
+       int ret = yaca_initialize();
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+}
+
+InitFixture::~InitFixture()
+{
+       yaca_cleanup();
+}
+
+struct TestConfig {
+       TestConfig()
+       {
+               boost::unit_test::unit_test_log.set_threshold_level(
+                       boost::unit_test::log_test_units);
+               boost::unit_test::results_reporter::set_level(boost::unit_test::SHORT_REPORT);
+       }
+       ~TestConfig()
+       {
+       }
+};
+
+BOOST_GLOBAL_FIXTURE(TestConfig);
+
+namespace {
+
+struct key_types {
+       yaca_key_type_e pub;
+       yaca_key_type_e params;
+};
+
+const std::map<yaca_key_type_e, key_types> KEY_TYPES = {
+       {YACA_KEY_TYPE_RSA_PRIV, {YACA_KEY_TYPE_RSA_PUB, YACA_INVALID_KEY_TYPE}},
+       {YACA_KEY_TYPE_DSA_PRIV, {YACA_KEY_TYPE_DSA_PUB, YACA_KEY_TYPE_DSA_PARAMS}},
+       {YACA_KEY_TYPE_DH_PRIV,  {YACA_KEY_TYPE_DH_PUB,  YACA_KEY_TYPE_DH_PARAMS}},
+       {YACA_KEY_TYPE_EC_PRIV,  {YACA_KEY_TYPE_EC_PUB,  YACA_KEY_TYPE_EC_PARAMS}},
+};
+
+} // namespace
+
+void generate_asymmetric_keys(yaca_key_type_e type_prv, size_t key_bit_len,
+                                                         yaca_key_h *key_prv, yaca_key_h *key_pub, yaca_key_h *key_params)
+{
+       int ret;
+       yaca_key_type_e type_pub, type_params;
+       yaca_key_h prv, pub, params;
+       type_pub = type_params = YACA_INVALID_KEY_TYPE;
+       prv = pub = params = YACA_KEY_NULL;
+
+       BOOST_REQUIRE_NO_THROW(type_pub = KEY_TYPES.at(type_prv).pub);
+       BOOST_REQUIRE_NO_THROW(type_params = KEY_TYPES.at(type_prv).params);
+
+       ret = yaca_key_generate(type_prv, key_bit_len, &prv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       if (key_pub != NULL && type_pub != YACA_INVALID_KEY_TYPE) {
+               ret = yaca_key_extract_public(prv, &pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+
+       if (key_params != NULL && type_params != YACA_INVALID_KEY_TYPE) {
+               ret = yaca_key_extract_parameters(prv, &params);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+
+       if (key_prv != NULL)
+               *key_prv = prv;
+       else
+               yaca_key_destroy(prv);
+
+       if (key_pub != NULL)
+               *key_pub = pub;
+
+       if (key_params != NULL)
+               *key_params = params;
+}
+
+size_t allocate_output(yaca_context_h ctx, size_t input_len, size_t split, char *&output)
+{
+       BOOST_REQUIRE_MESSAGE(split >= 1, "Fix your test");
+
+       int ret;
+       size_t part = input_len / split;
+       size_t parts = part * split;
+       size_t len1 = 0, len2 = 0, len3 = 0;
+
+       BOOST_REQUIRE_MESSAGE(part >= 1, "Fix your test");
+
+       ret = yaca_context_get_output_length(ctx, part, &len1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       if (parts < input_len) {
+               ret = yaca_context_get_output_length(ctx, input_len - parts, &len2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+       ret = yaca_context_get_output_length(ctx, 0, &len3);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       size_t total = len1 * split + len2 + len3;
+
+       ret = yaca_zalloc(total, reinterpret_cast<void**>(&output));
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       return total;
+}
+
+void call_update_loop(yaca_context_h ctx, const char *input, size_t input_len,
+                                         char *output, size_t &output_len, size_t split,
+                                         update_fun_5_t *fun)
+{
+       BOOST_REQUIRE_MESSAGE(split >= 1, "Fix your test");
+
+       int ret;
+       size_t left = input_len;
+       size_t part = input_len / split;
+       size_t written;
+
+       BOOST_REQUIRE_MESSAGE(part >= 1, "Fix your test");
+       output_len = 0;
+
+       for (;;) {
+               ret = fun(ctx, input, part, output, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               output_len += written;
+               output += written;
+               input += part;
+               left -= part;
+
+               if (left == 0)
+                       break;
+
+               if (left < part)
+                       part = left;
+       }
+}
diff --git a/tests/common.h b/tests/common.h
new file mode 100644 (file)
index 0000000..6c661e3
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    common.h
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Common headers for YACA unit tests
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <boost/test/unit_test.hpp>
+
+#include <yaca_crypto.h>
+#include <yaca_error.h>
+#include "../src/debug.h"
+
+
+constexpr size_t INPUT_DATA_SIZE = 4096;
+constexpr char INPUT_DATA[INPUT_DATA_SIZE] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus congue semper ipsum, ac convallis magna rhoncus sit amet. Donec pellentesque maximus convallis. Mauris ut egestas sem. Maecenas efficitur suscipit auctor. Nunc malesuada laoreet porttitor. Donec gravida tortor nisi, in mattis lectus porta ut. Integer vehicula eros et tellus placerat, nec fermentum justo aliquet.\
+Maecenas metus massa, ultrices et ultricies sed, imperdiet nec dolor. Nam eget massa eros. Proin vitae laoreet metus, at scelerisque massa. Nullam convallis dolor id nisl iaculis, a gravida risus pretium. Proin non nunc eget nibh fermentum dignissim. Nullam tristique, odio eget rutrum sagittis, tortor purus cursus nunc, nec iaculis quam nunc ac metus. Cras ut tortor a eros porta vehicula non at lectus. Aliquam volutpat quis nisi ut mattis. Curabitur semper vehicula ultrices. Aenean cursus laoreet venenatis. Aenean vulputate, nisl id facilisis fringilla, neque velit posuere libero, et viverra tortor felis vitae urna. Sed in congue nunc. Fusce molestie tempor pharetra. Cras sodales pulvinar nunc non sollicitudin.\
+Maecenas vehicula metus ac tristique ultricies. Suspendisse potenti. Pellentesque suscipit egestas augue, sed dictum orci. Pellentesque eu lorem ultricies, vestibulum est in, bibendum turpis. Proin placerat tincidunt metus, eget volutpat dolor. Pellentesque varius leo eget velit lobortis, sit amet congue orci bibendum. Aliquam vitae posuere lorem. Donec sed convallis diam. Quisque aliquam interdum purus, eu ornare ex ullamcorper iaculis. In sit amet nisl eu nisl ultricies dapibus. Aenean finibus efficitur elit ut sodales. Nam sit amet auctor sem, eu iaculis nunc. Vivamus mattis arcu a viverra faucibus. In dignissim, nisi sit amet consectetur tempus, lorem dui fringilla augue, sit amet lacinia lectus sapien efficitur odio.\
+Nullam et egestas enim. Nam sit amet mi malesuada, dapibus felis quis, viverra mauris. Ut quis enim eu neque porta vehicula. Etiam ullamcorper vitae turpis vehicula blandit. Maecenas blandit tristique semper. Aliquam at sagittis enim. Donec quis molestie urna. Duis ut urna blandit, pellentesque magna ultrices, dignissim mi. Morbi fermentum ex massa, ut facilisis est tincidunt vel. Nam sed erat in lacus molestie mattis quis ut leo. Phasellus tempus elit urna, eget sagittis purus volutpat sed. Suspendisse aliquam, sem vel gravida lobortis, tortor orci ornare nisi, sed mollis ligula sem nec risus. In a ex nibh. Praesent odio est, molestie sed vestibulum id, varius sit amet lectus. Donec vel diam efficitur, tristique ligula a, aliquet felis. Nullam sit amet neque tellus.\
+Phasellus aliquet non libero non aliquet. Aliquam efficitur ultrices tortor vitae lobortis. Pellentesque sed dolor quis nisl faucibus eleifend vitae ultrices est. Integer et libero quis nisl sollicitudin volutpat sit amet a quam. Vivamus commodo dolor augue, volutpat dapibus odio dapibus et. Nulla sed congue nisl. Duis nunc sem, condimentum nec neque ac, blandit blandit quam. Integer tincidunt ipsum nec risus viverra mollis. In porta porttitor mattis. Nulla ac eleifend nibh. Vivamus suscipit at nunc ac interdum. In fermentum fringilla odio.\
+Sed nec erat eget mauris varius pulvinar. Ut fermentum ante non erat elementum, vitae tempor velit blandit. Curabitur turpis tellus, sodales sit amet mattis nec, volutpat ac magna. Nulla quam orci, rutrum sit amet imperdiet ut, iaculis in nisl. Donec semper vitae tellus nec bibendum. Nam pharetra hendrerit sapien quis rutrum. Morbi tincidunt justo ut sodales ullamcorper. Suspendisse eget pellentesque nulla, non placerat purus. Donec placerat id turpis in interdum. Curabitur lobortis risus et placerat commodo. Morbi pulvinar eros leo, scelerisque rutrum arcu pretium at. Quisque eget diam dui. Quisque bibendum luctus arcu quis semper. Nullam erat lacus, lacinia sit amet neque aliquam, lacinia maximus lorem.\
+Nunc ac purus vel sem laoreet interdum quis eget ligula. Aenean id nisl ut quam vehicula pretium sed sit amet urna. Aenean diam lorem, vehicula et sapien nec, pellentesque consectetur libero. Cras fringilla nibh eu libero nullam.";
+
+constexpr size_t IGNORE = static_cast<size_t>(-1);
+
+#define DEFINE_INVALID(type, name) \
+       constexpr type YACA_INVALID_##name = static_cast<type>(-1)
+
+DEFINE_INVALID(yaca_error_e,                 ERROR);
+DEFINE_INVALID(yaca_key_format_e,            KEY_FORMAT);
+DEFINE_INVALID(yaca_key_file_format_e,       KEY_FILE_FORMAT);
+DEFINE_INVALID(yaca_key_type_e,              KEY_TYPE);
+DEFINE_INVALID(yaca_key_bit_length_e,        KEY_BIT_LENGTH);
+DEFINE_INVALID(yaca_key_bit_length_ec_e,     KEY_BIT_LENGTH_EC);
+DEFINE_INVALID(yaca_key_bit_length_dh_rfc_e, KEY_BIT_LENGTH_DH_RFC);
+DEFINE_INVALID(yaca_digest_algorithm_e,      DIGEST_ALGORITHM);
+DEFINE_INVALID(yaca_encrypt_algorithm_e,     ENCRYPT_ALGORITHM);
+DEFINE_INVALID(yaca_block_cipher_mode_e,     BLOCK_CIPHER_MODE);
+DEFINE_INVALID(yaca_property_e,              PROPERTY);
+DEFINE_INVALID(yaca_padding_e,               PADDING);
+DEFINE_INVALID(yaca_kdf_e,                   KDF);
+
+
+struct DebugFixture {
+       DebugFixture();
+       ~DebugFixture();
+};
+
+struct InitFixture {
+       InitFixture();
+       ~InitFixture();
+};
+
+struct InitDebugFixture {
+       InitFixture init;
+       DebugFixture debug;
+};
+
+void generate_asymmetric_keys(yaca_key_type_e type_prv, size_t key_bit_len,
+                                                         yaca_key_h *key_prv,
+                                                         yaca_key_h *key_pub = NULL, yaca_key_h *key_params = NULL);
+
+size_t allocate_output(yaca_context_h ctx, size_t input_len, size_t split, char *&output);
+
+using update_fun_5_t = int(yaca_context_h ctx, const char *plaintext, size_t plaintext_len,
+                                                  char *ciphertext, size_t *ciphertext_len);
+
+void call_update_loop(yaca_context_h ctx, const char *input, size_t input_len,
+                                         char *output, size_t &output_len, size_t split,
+                                         update_fun_5_t *fun);
+
+#endif /* COMMON_H */
diff --git a/tests/test_crypto.cpp b/tests/test_crypto.cpp
new file mode 100644 (file)
index 0000000..2c16460
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_crypto.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Base crypto API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include <openssl/rand.h>
+
+#include <yaca_crypto.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+namespace {
+
+const size_t DATA_SIZE = 10;
+
+bool is_mem_zero(const char* p, size_t size)
+{
+       for (size_t i = 0; i < size; ++i)
+               if (p[i] != '\0')
+                       return false;
+       return true;
+}
+
+}
+
+BOOST_AUTO_TEST_SUITE(TESTS_CRYPTO)
+
+BOOST_FIXTURE_TEST_CASE(T101__positive__init, DebugFixture)
+{
+       int ret;
+
+       ret = yaca_initialize();
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       yaca_cleanup();
+}
+
+BOOST_FIXTURE_TEST_CASE(T102__negative__double_init, DebugFixture)
+{
+       int ret;
+
+       ret = yaca_initialize();
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_initialize();
+       BOOST_REQUIRE(ret == YACA_ERROR_INTERNAL);
+
+       yaca_cleanup();
+}
+
+BOOST_FIXTURE_TEST_CASE(T103__negative__double_cleanup, DebugFixture)
+{
+       int ret;
+
+       ret = yaca_initialize();
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       yaca_cleanup();
+
+       yaca_cleanup();
+}
+
+BOOST_FIXTURE_TEST_CASE(T104__positivie__malloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_malloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(alloc != NULL);
+
+       yaca_free(alloc);
+}
+
+BOOST_FIXTURE_TEST_CASE(T105__negative__malloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_malloc(0, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_malloc(DATA_SIZE, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_malloc(0, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T106__positive__zalloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(alloc != NULL);
+
+       BOOST_REQUIRE(is_mem_zero(alloc, DATA_SIZE));
+
+       yaca_free(alloc);
+}
+
+BOOST_FIXTURE_TEST_CASE(T107__negative__zalloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_zalloc(0, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_zalloc(DATA_SIZE, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_zalloc(0, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T108__positive__realloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_realloc(DATA_SIZE * 2, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(alloc != NULL);
+
+       BOOST_REQUIRE(is_mem_zero(alloc, DATA_SIZE));
+
+       ret = yaca_realloc(DATA_SIZE / 2, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(alloc != NULL);
+
+       BOOST_REQUIRE(is_mem_zero(alloc, DATA_SIZE / 2));
+
+       yaca_free(alloc);
+       alloc = NULL;
+
+       ret = yaca_realloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(alloc != NULL);
+
+       yaca_free(alloc);
+}
+
+BOOST_FIXTURE_TEST_CASE(T109__negative__realloc, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_realloc(0, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+       BOOST_REQUIRE(is_mem_zero(alloc, DATA_SIZE));
+
+       ret = yaca_realloc(DATA_SIZE, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_realloc(0, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_free(alloc);
+}
+
+BOOST_FIXTURE_TEST_CASE(T110__positive__memcmp, InitDebugFixture)
+{
+       int ret;
+       char *alloc1, *alloc2;
+
+       ret = yaca_memcmp(NULL, NULL, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(alloc1, alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(alloc1, alloc2, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(NULL, alloc2, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(alloc1, NULL, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       alloc1[9] = 'a';
+
+       ret = yaca_memcmp(alloc1, alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_memcmp(alloc1, alloc2, 9);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       alloc2[0] = 'a';
+
+       ret = yaca_memcmp(alloc1, alloc2, 9);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_memcmp(alloc1, alloc1, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(alloc2, alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       yaca_free(alloc1);
+       yaca_free(alloc2);
+}
+
+BOOST_FIXTURE_TEST_CASE(T111__negative__memcmp, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_malloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_memcmp(alloc, NULL, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_memcmp(NULL, alloc, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_free(alloc);
+}
+
+BOOST_FIXTURE_TEST_CASE(T112__positive__yaca_randomize_bytes, InitDebugFixture)
+{
+       int ret;
+       char *alloc1, *alloc2;
+
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_zalloc(DATA_SIZE, (void**)&alloc2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_randomize_bytes(alloc1, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(!is_mem_zero(alloc1, DATA_SIZE));
+
+       ret = yaca_memcmp(alloc1, alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_randomize_bytes(alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(!is_mem_zero(alloc2, DATA_SIZE));
+
+       ret = yaca_memcmp(alloc1, alloc2, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       yaca_free(alloc1);
+       yaca_free(alloc2);
+}
+
+BOOST_FIXTURE_TEST_CASE(T113__negative__yaca_randomize_bytes, InitDebugFixture)
+{
+       int ret;
+       char *alloc;
+
+       ret = yaca_malloc(DATA_SIZE, (void**)&alloc);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_randomize_bytes(alloc, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_randomize_bytes(NULL, DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+}
+
+BOOST_FIXTURE_TEST_CASE(T114__negative__yaca_context, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_padding_e *get, set = YACA_PADDING_NONE;
+       size_t output, input = sizeof(yaca_padding_e);
+
+       ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, (void*)&set, input);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING, (void**)&get, &output);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_get_output_length(ctx, 0, &output);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T115__positive__openssl_rand, InitDebugFixture)
+{
+       static const size_t LEN = 256;
+       int ret;
+       unsigned char rand_bytes[LEN] = {};
+
+       ret = RAND_status();
+       BOOST_REQUIRE(ret == 1);
+
+       BOOST_REQUIRE(is_mem_zero((const char *)rand_bytes, LEN));
+       ret = RAND_bytes(rand_bytes, LEN);
+       BOOST_REQUIRE(ret == 1);
+       BOOST_REQUIRE(!is_mem_zero((const char *)rand_bytes, LEN));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_debug.cpp b/tests/test_debug.cpp
new file mode 100644 (file)
index 0000000..3786abd
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_debug.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Debug internal API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <vector>
+#include <iostream>
+
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/pem.h>
+#include <openssl/ec.h>
+
+#include <yaca_error.h>
+#include "../src/debug.h"
+#include "common.h"
+
+
+namespace {
+
+int error_cb_called = 0;
+
+/* Has to be the same as BUF_SIZE in error_dump */
+const size_t BUF_SIZE = 512;
+/* Has to be the same as ELLIPSIS in error_dump */
+const char ELLIPSIS[] = "...\n";
+
+char last_buf[BUF_SIZE] = {};
+
+void debug_error_cb(const char *buf)
+{
+       ++error_cb_called;
+
+       BOOST_REQUIRE(strlen(buf) < BUF_SIZE);
+       memcpy(last_buf, buf, BUF_SIZE);
+}
+
+struct CallbackCleanup
+{
+       CallbackCleanup()
+       {
+               error_cb_called = 0;
+       }
+       ~CallbackCleanup()
+       {
+               yaca_debug_set_error_cb(NULL);
+       }
+};
+
+}
+
+BOOST_AUTO_TEST_SUITE(TESTS_DEBUG)
+
+BOOST_AUTO_TEST_CASE(T001__neutral__translate_error)
+{
+       struct error_args {
+               yaca_error_e err;
+               std::string msg;
+       };
+
+       const std::vector<struct error_args> eargs = {
+               {YACA_INVALID_ERROR, "Error not defined"},
+               {YACA_ERROR_NONE, "YACA_ERROR_NONE"},
+               {YACA_ERROR_INVALID_PARAMETER, "YACA_ERROR_INVALID_PARAMETER"},
+               {YACA_ERROR_OUT_OF_MEMORY, "YACA_ERROR_OUT_OF_MEMORY"},
+               {YACA_ERROR_INTERNAL, "YACA_ERROR_INTERNAL"},
+               {YACA_ERROR_DATA_MISMATCH, "YACA_ERROR_DATA_MISMATCH"},
+               {YACA_ERROR_INVALID_PASSWORD, "YACA_ERROR_INVALID_PASSWORD"},
+       };
+
+       for (const auto &ea: eargs) {
+               std::string ret = yaca_debug_translate_error(ea.err);
+               BOOST_REQUIRE(ret == ea.msg);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T002__neutral__debug_set_error_cb, CallbackCleanup)
+{
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 0);
+
+       yaca_debug_set_error_cb(&debug_error_cb);
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 1);
+
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 2);
+
+       yaca_debug_set_error_cb(NULL);
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 2);
+}
+
+BOOST_FIXTURE_TEST_CASE(T003__neutral__error_dump, CallbackCleanup)
+{
+       yaca_debug_set_error_cb(&debug_error_cb);
+
+       /* I won't check the string that's been generated. It's too
+        * volatile. Some regexp can be implemented at most. */
+       PEMerr(PEM_F_LOAD_IV, PEM_R_READ_KEY);
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 1);
+       RSAerr(RSA_F_RSA_VERIFY, RSA_R_DATA_TOO_LARGE);
+       ERROR_DUMP(-1 * YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 2);
+
+       /* The check that makes sense though is ellipsis. Also it'll
+        * trigger the ellipsis code so it's at least a crash check.
+        * No, those errors don't have to make any sense. */
+       RSAerr(RSA_F_PKEY_RSA_CTRL, RSA_R_KEY_SIZE_TOO_SMALL);
+       RSAerr(RSA_F_RSA_SIGN, RSA_R_MODULUS_TOO_LARGE);
+       DSAerr(DSA_F_PKEY_DSA_KEYGEN, DSA_R_PARAMETER_ENCODING_ERROR);
+       DSAerr(DSA_F_DSA_SIGN_SETUP, DSA_R_MODULUS_TOO_LARGE);
+       PEMerr(PEM_F_PEM_ASN1_WRITE, PEM_R_BAD_PASSWORD_READ);
+       PEMerr(PEM_F_PEM_READ_DHPARAMS, PEM_R_UNSUPPORTED_CIPHER);
+       PEMerr(PEM_F_PEM_READ_BIO_EX, PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
+       RSAerr(RSA_F_ENCODE_PKCS1, RSA_R_VALUE_MISSING);
+       ERROR_DUMP(YACA_ERROR_INTERNAL);
+       BOOST_REQUIRE(error_cb_called == 3);
+
+       std::string ret(last_buf);
+       std::string ellipsis = ret.substr(ret.size() - strlen(ELLIPSIS));
+       BOOST_REQUIRE(ellipsis == ELLIPSIS);
+}
+
+BOOST_FIXTURE_TEST_CASE(T004__neutral__error_handle, CallbackCleanup)
+{
+       struct error_args {
+               long err1;
+               long err2;
+               yaca_error_e expected;
+               int cb_called;
+       };
+
+       const std::vector<struct error_args> eargs = {
+               {-1, -1, YACA_ERROR_INTERNAL, 0},
+               {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_OSSL_PRIVATE_DECRYPT, RSA_R_DATA_GREATER_THAN_MOD_LEN),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_RSA, RSA_F_PKEY_RSA_CTRL, RSA_R_KEY_SIZE_TOO_SMALL),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_TOO_LONG),
+                ERR_PACK(ERR_LIB_RSA, RSA_F_OLD_RSA_PRIV_DECODE, ERR_R_RSA_LIB),
+                YACA_ERROR_INVALID_PASSWORD, 0},
+               {ERR_PACK(ERR_LIB_ASN1, ASN1_F_ASN1_GET_OBJECT, ASN1_R_HEADER_TOO_LONG),
+                ERR_PACK(ERR_LIB_RSA, RSA_F_OLD_RSA_PRIV_DECODE, RSA_R_DIGEST_NOT_ALLOWED),
+                YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_READ_BIO_PRIVATEKEY, PEM_R_BAD_PASSWORD_READ),
+                -1, YACA_ERROR_INVALID_PASSWORD, 0},
+               {ERR_PACK(ERR_LIB_PEM, PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT),
+                -1, YACA_ERROR_INVALID_PASSWORD, 0},
+               {ERR_PACK(ERR_LIB_RSA, RSA_F_CHECK_PADDING_MD, PEM_R_BAD_DECRYPT),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_RSA, RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, PEM_R_BAD_DECRYPT),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, ERR_R_MALLOC_FAILURE),
+                -1, YACA_ERROR_OUT_OF_MEMORY, 0},
+               {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, ERR_R_PASSED_NULL_PARAMETER),
+                -1, YACA_ERROR_INVALID_PARAMETER, 0},
+               {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, ERR_R_INTERNAL_ERROR),
+                -1, YACA_ERROR_INTERNAL, 0},
+               {ERR_PACK(ERR_LIB_EC, EC_F_PKEY_EC_SIGN, ERR_R_DISABLED),
+                -1, YACA_ERROR_INTERNAL, 0},
+               {ERR_PACK(ERR_LIB_RSA, RSA_F_SETUP_TBUF, RSA_R_BAD_SIGNATURE),
+                -1, YACA_ERROR_INTERNAL, 1},
+               {ERR_PACK(ERR_LIB_DSA, DSA_F_DSA_NEW_METHOD, DSA_R_BN_ERROR),
+                -1, YACA_ERROR_INTERNAL, 1},
+               {ERR_PACK(ERR_LIB_EC, EC_F_BN_TO_FELEM, EC_R_SLOT_FULL),
+                -1, YACA_ERROR_INTERNAL, 1},
+       };
+
+       yaca_debug_set_error_cb(&debug_error_cb);
+
+       for (const auto &ea: eargs) {
+               error_cb_called = 0;
+
+               if (ea.err1 != -1) {
+                       ERR_PUT_error(ERR_GET_LIB(ea.err1), ERR_GET_FUNC(ea.err1),
+                                                 ERR_GET_REASON(ea.err1), OPENSSL_FILE, OPENSSL_LINE);
+               }
+               if (ea.err2 != -1) {
+                       ERR_PUT_error(ERR_GET_LIB(ea.err2), ERR_GET_FUNC(ea.err2),
+                                                 ERR_GET_REASON(ea.err2), OPENSSL_FILE, OPENSSL_LINE);
+               }
+
+               int ret = ERROR_HANDLE();
+
+               BOOST_REQUIRE(ret == ea.expected);
+               BOOST_REQUIRE(error_cb_called == ea.cb_called);
+       }
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_digest.cpp b/tests/test_digest.cpp
new file mode 100644 (file)
index 0000000..c6b63c9
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_digest.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Digest API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_digest.h>
+#include <yaca_encrypt.h>
+#include <yaca_key.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_DIGEST)
+
+BOOST_FIXTURE_TEST_CASE(T501__positive__yaca_digest, InitDebugFixture)
+{
+       struct digest_args {
+               yaca_digest_algorithm_e algo = YACA_DIGEST_SHA256;
+               size_t expected;
+               size_t split;
+       };
+
+       const std::vector<struct digest_args> dargs = {
+               {yaca_digest_algorithm_e::YACA_DIGEST_MD5,    16, 5},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA1,   20, 15},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA224, 28, 9},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA256, 32, 7},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA384, 48, 35},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA512, 64, 11}
+       };
+
+       for (const auto &da: dargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               char *digest = NULL;
+               size_t digest_len;
+
+               ret = yaca_digest_initialize(&ctx, da.algo);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               const char *input = INPUT_DATA;
+               size_t left = INPUT_DATA_SIZE;
+               size_t todo = INPUT_DATA_SIZE / da.split;
+               BOOST_REQUIRE_MESSAGE(todo > 0, "Fix your test");
+
+               for (;;) {
+                       ret = yaca_digest_update(ctx, input, todo);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       input += todo;
+                       left -= todo;
+
+                       if (left == 0)
+                               break;
+
+                       if (left < todo)
+                               todo = left;
+               }
+
+               ret = yaca_context_get_output_length(ctx, 0, &digest_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(digest_len, (void**)&digest);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(digest != NULL);
+
+               ret = yaca_digest_finalize(ctx, digest, &digest_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(digest_len == da.expected);
+
+               yaca_context_destroy(ctx);
+               yaca_free(digest);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T502__negative__yaca_digest, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_context_h ctx_encrypt = YACA_CONTEXT_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL;
+       char *digest = NULL;
+       size_t digest_len;
+       yaca_padding_e pad = YACA_PADDING_PKCS1;
+       size_t bit_len = 256;
+
+       ret = yaca_digest_initialize(NULL, YACA_DIGEST_MD5);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_initialize(&ctx, YACA_INVALID_DIGEST_ALGORITHM);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_initialize(&ctx, YACA_DIGEST_MD5);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key_sym);
+       ret = yaca_encrypt_initialize(&ctx_encrypt, YACA_ENCRYPT_AES,
+                                                                 YACA_BCM_ECB, key_sym, YACA_KEY_NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                       &pad, sizeof(yaca_padding_e));
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                       &bit_len, sizeof(size_t));
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_update(NULL, INPUT_DATA, INPUT_DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_update(ctx_encrypt, INPUT_DATA, INPUT_DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_update(ctx, NULL, INPUT_DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_update(ctx, INPUT_DATA, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_context_get_output_length(YACA_CONTEXT_NULL, 0, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_get_output_length(ctx, 10, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_get_output_length(ctx, 0, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_context_get_output_length(ctx, 0, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_malloc(digest_len, (void**)&digest);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_digest_finalize(YACA_CONTEXT_NULL, digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_finalize(ctx_encrypt, digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_finalize(ctx, NULL, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_finalize(ctx, digest, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_finalize(ctx, digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_digest_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_digest_finalize(ctx, digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_context_destroy(ctx);
+       yaca_context_destroy(ctx_encrypt);
+       yaca_key_destroy(key_sym);
+       yaca_free(digest);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_encrypt.cpp b/tests/test_encrypt.cpp
new file mode 100644 (file)
index 0000000..92565a6
--- /dev/null
@@ -0,0 +1,2402 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_encrypt.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Encrypt API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+#include <cstring>
+#include <iostream>
+
+#include <yaca_crypto.h>
+#include <yaca_encrypt.h>
+#include <yaca_key.h>
+#include <yaca_digest.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+namespace {
+
+yaca_key_h generate_iv(yaca_encrypt_algorithm_e algo, yaca_block_cipher_mode_e bcm,
+                                          size_t key_bit_len, size_t iv_bit_len = IGNORE)
+{
+       int ret;
+       yaca_key_h iv = YACA_KEY_NULL;
+
+       if (iv_bit_len == IGNORE) {
+               ret = yaca_encrypt_get_iv_bit_length(algo, bcm, key_bit_len, &iv_bit_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+
+       if (iv_bit_len > 0) {
+               ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+
+       return iv;
+}
+
+} // namespace
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_ENCRYPT)
+
+BOOST_FIXTURE_TEST_CASE(T601__positive__get_iv_bit_length, InitDebugFixture)
+{
+       struct iv_args {
+               yaca_encrypt_algorithm_e algo;
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+               size_t expected_iv_bit_len;
+       };
+
+       const std::vector<iv_args> iargs = {
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CCM,  128,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128,   0},
+               {YACA_ENCRYPT_AES, YACA_BCM_GCM,  128,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  128, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_WRAP, 128,  64},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CCM,  192,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192,   0},
+               {YACA_ENCRYPT_AES, YACA_BCM_GCM,  192,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  192, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_WRAP, 192,  64},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CCM,  256,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256,   0},
+               {YACA_ENCRYPT_AES, YACA_BCM_GCM,  256,  96},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  256, 128},
+               {YACA_ENCRYPT_AES, YACA_BCM_WRAP, 256,  64},
+
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, 64},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB,  64, 64},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB1, 64, 64},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB8, 64, 64},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64,  0},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_OFB,  64, 64},
+
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, 64},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CFB, 128, 64},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128,  0},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_OFB, 128, 64},
+
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, 64},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB,  192, 64},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB1, 192, 64},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB8, 192, 64},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192,  0},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_OFB,  192, 64},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_WRAP, 192,  0},
+
+               {YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, 192, 64},
+               {YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CFB, 192, 64},
+               {YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_ECB, 192,  0},
+               {YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_OFB, 192, 64},
+
+               {YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE, 256, 0},
+
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, 64},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CFB, 128, 64},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128,  0},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_OFB, 128, 64},
+       };
+
+       for (const auto &ia: iargs) {
+               int ret;
+               size_t iv_bit_len;
+
+               ret = yaca_encrypt_get_iv_bit_length(ia.algo, ia.bcm, ia.key_bit_len, &iv_bit_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(iv_bit_len == ia.expected_iv_bit_len);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T602__negative__get_iv_bit_length, InitDebugFixture)
+{
+       int ret;
+       size_t iv_bit_len;
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_256BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE,
+                                                                                YACA_KEY_LENGTH_256BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                0, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                1, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                8, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_256BIT, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_UNSAFE_64BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_192BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_192BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_2048BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE,
+                                                                                YACA_KEY_LENGTH_4096BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_CAST5, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_UNSAFE_8BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T603__positive__encrypt_decrypt, InitDebugFixture)
+{
+       struct encrypt_args {
+               yaca_encrypt_algorithm_e algo;
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+               yaca_padding_e padding;
+               size_t split;
+       };
+
+       const std::vector<encrypt_args> eargs = {
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_INVALID_PADDING, 16},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_PADDING_NONE,     8},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_PADDING_PKCS7,   11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  128, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 128, YACA_INVALID_PADDING, 13},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 128, YACA_INVALID_PADDING,  4},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  128, YACA_INVALID_PADDING, 66},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_INVALID_PADDING,  3},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_PADDING_PKCS7,   34},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  128, YACA_INVALID_PADDING, 27},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_PADDING_NONE,    12},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_PADDING_PKCS7,   11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  192, YACA_INVALID_PADDING, 31},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 192, YACA_INVALID_PADDING, 17},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 192, YACA_INVALID_PADDING,  2},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  192, YACA_INVALID_PADDING,  1},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_PADDING_NONE,    15},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_PADDING_PKCS7,   33},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  192, YACA_INVALID_PADDING, 44},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_INVALID_PADDING, 10},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_PADDING_PKCS7,   23},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  256, YACA_INVALID_PADDING, 17},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 256, YACA_INVALID_PADDING, 23},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 256, YACA_INVALID_PADDING, 29},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  256, YACA_INVALID_PADDING, 21},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_PADDING_NONE,     3},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_PADDING_PKCS7,   15},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  256, YACA_INVALID_PADDING, 13},
+
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_INVALID_PADDING, 31},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_PADDING_NONE,    22},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_PADDING_PKCS7,   39},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB,  64, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB1, 64, YACA_INVALID_PADDING, 11},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB8, 64, YACA_INVALID_PADDING, 22},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_INVALID_PADDING,  7},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_PADDING_NONE,    19},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_PADDING_PKCS7,    9},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_OFB,  64, YACA_INVALID_PADDING,  2},
+
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_INVALID_PADDING, 16},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_PADDING_NONE,    25},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_PADDING_PKCS7,   26},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CFB, 128, YACA_INVALID_PADDING, 23},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_INVALID_PADDING, 13},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_PADDING_NONE,    10},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_PADDING_PKCS7,   29},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_OFB, 128, YACA_INVALID_PADDING, 32},
+
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_INVALID_PADDING, 39},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_PADDING_NONE,    29},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_PADDING_PKCS7,   19},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB,  192, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB1, 192, YACA_INVALID_PADDING, 44},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB8, 192, YACA_INVALID_PADDING, 33},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_INVALID_PADDING, 22},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_PADDING_PKCS7,   13},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_OFB,  192, YACA_INVALID_PADDING,  1},
+
+               {YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE, 256, YACA_INVALID_PADDING, 17},
+
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_INVALID_PADDING,  3},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_PADDING_NONE,    24},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_PADDING_PKCS7,   21},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CFB, 128, YACA_INVALID_PADDING, 19},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_INVALID_PADDING,  7},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_PADDING_NONE,     6},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_PADDING_PKCS7,   18},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_OFB, 128, YACA_INVALID_PADDING,  2},
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               iv = generate_iv(ea.algo, ea.bcm, ea.key_bit_len);
+
+               /* ENCRYPT */
+               {
+                       ret = yaca_encrypt_initialize(&ctx, ea.algo, ea.bcm, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, ea.split, encrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, ea.split,
+                                                        &yaca_encrypt_update);
+
+                       if (ea.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &ea.padding,
+                                                                                               sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* DECRYPT */
+               {
+                       ret = yaca_decrypt_initialize(&ctx, ea.algo, ea.bcm, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (ea.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &ea.padding,
+                                                                                               sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, encrypted_len, ea.split, decrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, ea.split,
+                                                        &yaca_decrypt_update);
+
+                       ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T604__negative__encrypt_decrypt, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL, ctx_digest = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+       yaca_key_h key2 = YACA_KEY_NULL, iv2 = YACA_KEY_NULL;
+       yaca_key_h key_rsa = YACA_KEY_NULL, iv_invalid = YACA_KEY_NULL;
+       yaca_padding_e pad_pkcs7 = YACA_PADDING_PKCS7;
+       yaca_padding_e pad_invalid = YACA_PADDING_X931;
+       yaca_padding_e *pad_get;
+       size_t key_bits_len = 128, pad_get_len;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len = 0, decrypted_len = 0;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_IV_128BIT, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_IV_128BIT, &iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 32, &iv_invalid);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_rsa);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_digest_initialize(&ctx_digest, YACA_DIGEST_MD5);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* ENCRYPT */
+       {
+               ret = yaca_encrypt_initialize(NULL, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, YACA_KEY_NULL, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, iv2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key_rsa, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv_invalid);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, key_rsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_ECB, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_CFB, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, INPUT_DATA_SIZE, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_encrypt_update(YACA_CONTEXT_NULL, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx_digest, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, 0, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, 0);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &key_bits_len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               (void**)&pad_get, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               NULL, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               (void**)&pad_get, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               (void**)&pad_get, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(YACA_CONTEXT_NULL, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx_digest, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT */
+       {
+               ret = yaca_decrypt_initialize(NULL, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, YACA_KEY_NULL, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, iv2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv_invalid);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, key_rsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_ECB, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_CFB, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, 0);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &key_bits_len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               (void**)&pad_get, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               NULL, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               (void**)&pad_get, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               (void**)&pad_get, &pad_get_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_output_length(ctx, encrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(YACA_CONTEXT_NULL, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx_digest, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, 0, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(YACA_CONTEXT_NULL, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx_digest, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len += written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong BCM */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_ECB, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &pad_pkcs7,
+                                                                               sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong key */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &pad_pkcs7,
+                                                                               sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, broken the end of ciphertext */
+       {
+               encrypted[encrypted_len - 1] = ~encrypted[encrypted_len - 1];
+               encrypted[encrypted_len - 2] = ~encrypted[encrypted_len - 2];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &pad_pkcs7,
+                                                                               sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_context_destroy(ctx_digest);
+       yaca_key_destroy(key);
+       yaca_key_destroy(key2);
+       yaca_key_destroy(iv);
+       yaca_key_destroy(iv2);
+       yaca_key_destroy(key_rsa);
+       yaca_free(encrypted);
+}
+
+BOOST_FIXTURE_TEST_CASE(T605__positive__encrypt_decrypt_wrap, InitDebugFixture)
+{
+       struct encrypt_args {
+               yaca_encrypt_algorithm_e algo;
+               size_t key_bit_len;
+               size_t key_material_len;
+       };
+
+       const std::vector<encrypt_args> eargs = {
+               {YACA_ENCRYPT_AES,        128, 192 / 8},
+               {YACA_ENCRYPT_AES,        192, 256 / 8},
+               {YACA_ENCRYPT_AES,        256, 128 / 8},
+               {YACA_ENCRYPT_3DES_3TDEA, 192, 128 / 8},
+               {YACA_ENCRYPT_3DES_3TDEA, 192, 192 / 8},
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+               char *key_material = NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               ret = yaca_zalloc(ea.key_material_len, (void**)&key_material);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_randomize_bytes(key_material, ea.key_material_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               iv = generate_iv(ea.algo, YACA_BCM_WRAP, ea.key_bit_len);
+
+               /* ENCRYPT */
+               {
+                       ret = yaca_encrypt_initialize(&ctx, ea.algo, YACA_BCM_WRAP, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, ea.key_material_len, 1, encrypted);
+                       size_t written;
+
+                       ret = yaca_encrypt_update(ctx, key_material, ea.key_material_len,
+                                                                         encrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len = written;
+
+                       ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* DECRYPT */
+               {
+                       ret = yaca_decrypt_initialize(&ctx, ea.algo, YACA_BCM_WRAP, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, encrypted_len, 1, decrypted);
+                       size_t written;
+
+                       ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len = written;
+
+                       ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == ea.key_material_len);
+               ret = yaca_memcmp(key_material, decrypted, decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_key_destroy(iv);
+               yaca_free(key_material);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T606__negative__encrypt_decrypt_wrap, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+       yaca_key_h key_des1 = YACA_KEY_NULL, key_des2 = YACA_KEY_NULL;
+       char *key_material_64 = NULL, *key_material_192 = NULL, *key_material_256 = NULL;
+
+       size_t len64 = 64 / 8, len192 = 192 / 8, len256 = 256 / 8;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len, decrypted_len;
+
+       ret = yaca_zalloc(len64, (void**)&key_material_64);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(key_material_64, len64);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_zalloc(len192, (void**)&key_material_192);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(key_material_192, len192);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_zalloc(len256, (void**)&key_material_256);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(key_material_256, len256);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_128BIT, &key_sym);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_64BIT, &key_des1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT, &key_des2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_IV_64BIT, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* ENCRYPT AES */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_DES,
+                                                                         YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_CAST5,
+                                                                         YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES,
+                                                                         YACA_BCM_WRAP, key_des1, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES,
+                                                                         YACA_BCM_WRAP, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES,
+                                                                         YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, len192, 1, encrypted);
+               size_t written;
+
+               ret = yaca_encrypt_update(ctx, key_material_64, len64,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT AES */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_DES,
+                                                                         YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_CAST5,
+                                                                         YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES,
+                                                                         YACA_BCM_WRAP, key_des1, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES,
+                                                                         YACA_BCM_WRAP, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_WRAP, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len - 1, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len += written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* ENCRYPT 3DES */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des1, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des2, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, len192, 1, encrypted);
+               size_t written;
+
+               ret = yaca_encrypt_update(ctx, key_material_64, len64,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, key_material_256, len256,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, key_material_192, len192,
+                                                                 encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT 3DES */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des1, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_3DES_3TDEA,
+                                                                         YACA_BCM_WRAP, key_des2, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len - 1, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len += written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key_sym);
+       yaca_key_destroy(key_des1);
+       yaca_key_destroy(key_des2);
+       yaca_key_destroy(iv);
+       yaca_free(key_material_64);
+       yaca_free(key_material_192);
+       yaca_free(key_material_256);
+       yaca_free(encrypted);
+}
+
+BOOST_FIXTURE_TEST_CASE(T607__positive__encrypt_decrypt_rc2, InitDebugFixture)
+{
+       struct encrypt_args {
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+               yaca_padding_e padding;
+               size_t effective_key_bits;
+               size_t split;
+       };
+
+       const std::vector<encrypt_args> eargs = {
+               {YACA_BCM_CBC, 128, YACA_INVALID_PADDING, IGNORE, 11},
+               {YACA_BCM_CBC, 192, YACA_PADDING_NONE,        64, 22},
+               {YACA_BCM_CBC, 200, YACA_PADDING_PKCS7,      128,  3},
+               {YACA_BCM_CBC, 192, YACA_INVALID_PADDING,    255,  7},
+               {YACA_BCM_CBC, 192, YACA_INVALID_PADDING,    713,  2},
+               {YACA_BCM_CBC, 224, YACA_INVALID_PADDING,      1, 19},
+               {YACA_BCM_CBC, 256, YACA_INVALID_PADDING,   1024, 19},
+               {YACA_BCM_CFB, 192, YACA_INVALID_PADDING, IGNORE, 13},
+               {YACA_BCM_CFB, 192, YACA_INVALID_PADDING,    333, 33},
+               {YACA_BCM_ECB, 272, YACA_INVALID_PADDING, IGNORE,  8},
+               {YACA_BCM_ECB, 192, YACA_PADDING_NONE,       666, 15},
+               {YACA_BCM_ECB, 192, YACA_PADDING_PKCS7,       21, 15},
+               {YACA_BCM_OFB, 520, YACA_INVALID_PADDING, IGNORE, 25},
+               {YACA_BCM_OFB, 224, YACA_INVALID_PADDING,    999, 35},
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               iv = generate_iv(YACA_ENCRYPT_UNSAFE_RC2, ea.bcm, ea.key_bit_len);
+
+               /* ENCRYPT */
+               {
+                       ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, ea.bcm, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (ea.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                                               &ea.padding, sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       if (ea.effective_key_bits != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                                               &ea.effective_key_bits, sizeof(size_t));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, ea.split, encrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, ea.split,
+                                                        &yaca_encrypt_update);
+
+                       ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* DECRYPT */
+               {
+                       ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, ea.bcm, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (ea.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                                               &ea.padding, sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       if (ea.effective_key_bits != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                                               &ea.effective_key_bits, sizeof(size_t));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, encrypted_len, ea.split, decrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, ea.split,
+                                                        &yaca_decrypt_update);
+
+                       ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T608__negative__encrypt_decrypt_rc2, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+       yaca_padding_e pad_invalid = YACA_PADDING_PKCS1_SSLV23;
+       size_t effective_bits_invalid1 = 0, effective_bits_invalid2 = 2048;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_IV_64BIT, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* ENCRYPT */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CFB1, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CTR, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, YACA_KEY_NULL, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &effective_bits_invalid1, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &effective_bits_invalid2, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CFB1, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CTR, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, YACA_KEY_NULL, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &effective_bits_invalid1, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &effective_bits_invalid2, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(iv);
+}
+
+BOOST_FIXTURE_TEST_CASE(T609__positive__encrypt_decrypt_ccm, InitDebugFixture)
+{
+       struct encrypt_args {
+               size_t key_bit_len;
+               size_t ccm_tag_len;
+               size_t aad_len;
+               size_t iv_bit_len;
+       };
+
+       const std::vector<encrypt_args> eargs = {
+               {128, IGNORE, IGNORE, IGNORE},
+               {128,      4, IGNORE, IGNORE},
+               {128, IGNORE,     13, IGNORE},
+               {128,      6,     23, IGNORE},
+               {128,     12,     19,     96},
+               {128,      8,     43,     64},
+
+               {192, IGNORE, IGNORE, IGNORE},
+               {192,     10, IGNORE, IGNORE},
+               {192, IGNORE,     21, IGNORE},
+               {192,      8,     17, IGNORE},
+               {192,     16,     29,     64},
+               {192,     10,     34,     96},
+
+               {256, IGNORE, IGNORE, IGNORE},
+               {256,     16, IGNORE, IGNORE},
+               {256, IGNORE,     55, IGNORE},
+               {256,     12,     33, IGNORE},
+               {256,      6,     22,     96},
+               {256,     10,     44,     64},
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *tag = NULL, *aad = NULL;
+               size_t tag_len;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               iv = generate_iv(YACA_ENCRYPT_AES, YACA_BCM_CCM, ea.key_bit_len, ea.iv_bit_len);
+
+               /* ENCRYPT */
+               {
+                       ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+                       size_t written;
+
+                       if (ea.ccm_tag_len != IGNORE) {
+                               tag_len = ea.ccm_tag_len;
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG_LEN,
+                                                                                               &tag_len, sizeof(tag_len));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       if (ea.aad_len != IGNORE) {
+                               ret = yaca_malloc(ea.aad_len, (void**)&aad);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_randomize_bytes(aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE,
+                                                                                 NULL, &written);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD,
+                                                                                               aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len = written;
+
+                       ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* DECRYPT */
+               {
+                       ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, encrypted_len, 1, decrypted);
+                       size_t written;
+
+                       ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (ea.aad_len != IGNORE) {
+                               ret = yaca_decrypt_update(ctx, NULL, encrypted_len,
+                                                                                 NULL, &written);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD,
+                                                                                               aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len = written;
+
+                       ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+               yaca_free(tag);
+               yaca_free(aad);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T610__negative__encrypt_decrypt_ccm, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, key2 = YACA_KEY_NULL;
+       yaca_key_h iv = YACA_KEY_NULL, iv2 = YACA_KEY_NULL;
+       yaca_key_h iv_invalid = YACA_KEY_NULL;
+
+       char *tag = NULL, *aad = NULL;
+       size_t tag_len = 0, tag_len_invalid = 17, aad_len = 55;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len, decrypted_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 96, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 96, &iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 128, &iv_invalid);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_malloc(aad_len, (void**)&aad);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(aad, aad_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* ENCRYPT, AAD without pre-update */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* ENCRYPT, pre-update without AAD */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(encrypted);
+               encrypted = NULL;
+       }
+
+       /* ENCRYPT */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv_invalid);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG_LEN,
+                                                                               &tag_len_invalid, sizeof(tag_len_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT, no TAG */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT, AAD without pre-update */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT, pre-update without AAD */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, no AAD */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv_invalid);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong key */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               /* In case of AES/CBC wrong key returned INVALID_PASS
+                * Why this inconsistency?
+                */
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong IV */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, broken TAG */
+       {
+               char *tag2 = NULL;
+               ret = yaca_malloc(tag_len, (void**)&tag2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)tag2, (void*)tag, tag_len);
+               tag2[0] = ~tag2[0];
+               tag2[1] = ~tag2[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag2, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(tag2);
+       }
+
+       /* DECRYPT, broken AAD */
+       {
+               char *aad2 = NULL;
+               ret = yaca_malloc(aad_len, (void**)&aad2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)aad2, (void*)aad, aad_len);
+               aad2[0] = ~aad2[0];
+               aad2[1] = ~aad2[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad2, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(aad2);
+       }
+
+       /* DECRYPT, broken ciphertext */
+       {
+               encrypted[0] = ~encrypted[0];
+               encrypted[1] = ~encrypted[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_CCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key2);
+       yaca_key_destroy(iv);
+       yaca_key_destroy(iv2);
+       yaca_free(encrypted);
+       yaca_free(tag);
+       yaca_free(aad);
+}
+
+BOOST_FIXTURE_TEST_CASE(T611__positive__encrypt_decrypt_gcm, InitDebugFixture)
+{
+       struct encrypt_args {
+               size_t key_bit_len;
+               size_t gcm_tag_len;
+               size_t aad_len;
+               size_t split;
+               size_t iv_bit_len;
+       };
+
+       const std::vector<encrypt_args> eargs = {
+               {128, IGNORE, IGNORE, 11, IGNORE},
+               {128,      4, IGNORE, 12, IGNORE},
+               {128, IGNORE,     21, 13, IGNORE},
+               {128,     13,     22, 14, IGNORE},
+               {128,     14,     80,  4,    128},
+               {128,     13,     22, 14,     96},
+
+               {192, IGNORE, IGNORE, 22, IGNORE},
+               {192,      8, IGNORE, 23, IGNORE},
+               {192, IGNORE,     32, 24, IGNORE},
+               {192,     15,     33, 25, IGNORE},
+               {192,     13,     30, 74,     64},
+               {192,     15,     37, 25,     96},
+
+               {256, IGNORE, IGNORE, 33, IGNORE},
+               {256,     14, IGNORE, 34, IGNORE},
+               {256, IGNORE,     17, 35, IGNORE},
+               {256,     16,     44, 36, IGNORE},
+               {256,     14,     12, 15,    128},
+               {256,     16,     45, 36,     96},
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               char *tag = NULL, *aad = NULL;
+               size_t tag_len;
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               iv = generate_iv(YACA_ENCRYPT_AES, YACA_BCM_GCM, ea.key_bit_len, ea.iv_bit_len);
+
+               /* ENCRYPT */
+               {
+                       ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, ea.split, encrypted);
+                       size_t written;
+
+                       if (ea.aad_len != IGNORE) {
+                               ret = yaca_malloc(ea.aad_len, (void**)&aad);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_randomize_bytes(aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD,
+                                                                                               aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, ea.split,
+                                                        yaca_encrypt_update);
+
+                       ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (ea.gcm_tag_len != IGNORE) {
+                               tag_len = ea.gcm_tag_len;
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG_LEN,
+                                                                                               &tag_len, sizeof(tag_len));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_context_get_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                                       (void**)&tag, &tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* DECRYPT */
+               {
+                       ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, encrypted_len, ea.split, decrypted);
+                       size_t written;
+
+                       if (ea.aad_len != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD,
+                                                                                               aad, ea.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, ea.split,
+                                                        yaca_decrypt_update);
+
+                       ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                                       tag, tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+               yaca_free(tag);
+               yaca_free(aad);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T612__negative__encrypt_decrypt_gcm, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, key2 = YACA_KEY_NULL;
+       yaca_key_h iv = YACA_KEY_NULL, iv2 = YACA_KEY_NULL;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len = 0, decrypted_len = 0;
+
+       char *tag = NULL, *aad = NULL;
+       size_t tag_len = 0, tag_len_invalid = 17, aad_len = 55;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 96, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, 96, &iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_malloc(aad_len, (void**)&aad);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(aad, aad_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* ENCRYPT */
+       {
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_encrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                               (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_encrypt_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG_LEN,
+                                                                               &tag_len_invalid, sizeof(tag_len_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                               (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* DECRYPT, no TAG */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, no AAD */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_decrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong key */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, wrong IV */
+       {
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, broken TAG */
+       {
+               char *tag2 = NULL;
+               ret = yaca_malloc(tag_len, (void**)&tag2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)tag2, (void*)tag, tag_len);
+               tag2[0] = ~tag2[0];
+               tag2[1] = ~tag2[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag2, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, broken AAD */
+       {
+               char *aad2 = NULL;
+               ret = yaca_malloc(aad_len, (void**)&aad2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)aad2, (void*)aad, aad_len);
+               aad2[0] = ~aad2[0];
+               aad2[1] = ~aad2[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad2, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* DECRYPT, broken ciphertext */
+       {
+               encrypted[0] = ~encrypted[0];
+               encrypted[1] = ~encrypted[1];
+
+               ret = yaca_decrypt_initialize(&ctx, YACA_ENCRYPT_AES, YACA_BCM_GCM, key, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_decrypt_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key2);
+       yaca_key_destroy(iv);
+       yaca_key_destroy(iv2);
+       yaca_free(encrypted);
+       yaca_free(tag);
+       yaca_free(aad);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_key.cpp b/tests/test_key.cpp
new file mode 100644 (file)
index 0000000..d2ba692
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_key.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Key API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_encrypt.h>
+#include <yaca_key.h>
+#include <yaca_simple.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+namespace {
+
+void import_export(yaca_key_h key, yaca_key_type_e expected_type,
+                                  yaca_key_bit_length_e expected_len, const char *password,
+                                  yaca_key_format_e format, yaca_key_file_format_e file_format)
+{
+       int ret;
+       yaca_key_h imported = YACA_KEY_NULL;
+
+       char *data1 = NULL, *data2 = NULL;
+       size_t data1_len = 0, data2_len = 0;
+       yaca_key_type_e key_type;
+       size_t key_length;
+
+       ret = yaca_key_export(key, format, file_format,
+                                                 password, &data1, &data1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(data1 != NULL);
+       BOOST_REQUIRE(data1_len > 0);
+
+       ret = yaca_key_import(expected_type, password, data1, data1_len, &imported);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(imported, &key_type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_get_bit_length(imported, &key_length);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       BOOST_REQUIRE(key_type == expected_type);
+       BOOST_REQUIRE(key_length == expected_len);
+
+       ret = yaca_key_export(imported, format, file_format,
+                                                 password, &data2, &data2_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(data2 != NULL);
+       BOOST_REQUIRE(data2_len > 0);
+
+       BOOST_REQUIRE(data1_len == data2_len);
+
+       if (password == NULL || password[0] == '\0') {
+               ret = yaca_memcmp(data1, data2, data1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       }
+
+       yaca_key_destroy(imported);
+       yaca_free(data1);
+       yaca_free(data2);
+}
+
+void assert_keys_identical(const yaca_key_h key1, const yaca_key_h key2)
+{
+       int ret;
+       char *data1 = NULL, *data2 = NULL;
+       size_t len1, len2, data1_len, data2_len;
+       yaca_key_type_e type1, type2;
+       yaca_key_file_format_e format;
+
+       ret = yaca_key_get_bit_length(key1, &len1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_get_bit_length(key2, &len2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       BOOST_REQUIRE(len1 == len2);
+
+       ret = yaca_key_get_type(key1, &type1);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_get_type(key2, &type2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       BOOST_REQUIRE(type1 == type2);
+
+       switch (type1) {
+       case YACA_KEY_TYPE_SYMMETRIC:
+       case YACA_KEY_TYPE_DES:
+       case YACA_KEY_TYPE_IV:
+               format = YACA_KEY_FILE_FORMAT_RAW;
+               break;
+       default:
+               format = YACA_KEY_FILE_FORMAT_DER;
+       }
+
+       ret = yaca_key_export(key1, YACA_KEY_FORMAT_DEFAULT, format,
+                                                 NULL, &data1, &data1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_export(key2, YACA_KEY_FORMAT_DEFAULT, format,
+                                                 NULL, &data2, &data2_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       BOOST_REQUIRE(data1_len == data2_len);
+
+       ret = yaca_memcmp(data1, data2, data1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       yaca_free(data1);
+       yaca_free(data2);
+}
+
+} // namespace
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_KEY)
+
+BOOST_FIXTURE_TEST_CASE(T201__positive__key_generate, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type;
+               size_t len;
+               size_t expected;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_SYMMETRIC,
+                YACA_KEY_LENGTH_256BIT,
+                YACA_KEY_LENGTH_256BIT},
+               {YACA_KEY_TYPE_SYMMETRIC,
+                200,
+                200},
+               {YACA_KEY_TYPE_SYMMETRIC,
+                104,
+                104},
+               {YACA_KEY_TYPE_DES,
+                YACA_KEY_LENGTH_192BIT,
+                YACA_KEY_LENGTH_192BIT},
+               {YACA_KEY_TYPE_IV,
+                YACA_KEY_LENGTH_512BIT,
+                YACA_KEY_LENGTH_512BIT},
+               {YACA_KEY_TYPE_RSA_PRIV,
+                YACA_KEY_LENGTH_2048BIT,
+                YACA_KEY_LENGTH_2048BIT},
+               {YACA_KEY_TYPE_RSA_PRIV,
+                520,
+                520},
+               {YACA_KEY_TYPE_RSA_PRIV,
+                1056,
+                1056},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                YACA_KEY_LENGTH_2048BIT,
+                YACA_KEY_LENGTH_2048BIT},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                576,
+                576},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                896,
+                896},
+               {YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_2048_224,
+                YACA_KEY_LENGTH_2048BIT},
+               {YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)(YACA_KEY_LENGTH_DH_GENERATOR_2 | 264),
+                264},
+               {YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)(YACA_KEY_LENGTH_DH_GENERATOR_5 | 376),
+                376},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP384R1,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP384R1}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+               yaca_key_type_e key_type;
+               size_t key_length;
+
+               ret = yaca_key_generate(ka.type, ka.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_get_type(key, &key_type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_get_bit_length(key, &key_length);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(key_type == ka.type);
+               BOOST_REQUIRE(key_length == ka.expected);
+
+               yaca_key_destroy(key);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T202__negative__key_generate, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key = YACA_KEY_NULL;
+
+       ret = yaca_key_generate(YACA_INVALID_KEY_TYPE, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PUB, YACA_KEY_LENGTH_1024BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DSA_PARAMS, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, 0, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, 255, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DES, 127, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PRIV, 2047, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DH_PRIV,
+                                                       YACA_KEY_LENGTH_DH_GENERATOR_2 | 192U, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DH_PRIV, YACA_KEYLEN_COMPONENT_TYPE_DH |
+                                                       YACA_KEYLEN_COMPONENT_DH_GEN_MASK | 1024U, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DH_PRIV, YACA_KEYLEN_COMPONENT_TYPE_MASK |
+                                                       YACA_KEYLEN_COMPONENT_DH_GEN_2 | 1024U, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_DH_PRIV, YACA_KEYLEN_COMPONENT_TYPE_DH_RFC, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_EC_PARAMS, YACA_KEYLEN_COMPONENT_EC_SECT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T203__positive__key_generate_from_parameters, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type_params;
+               yaca_key_type_e type_key;
+               yaca_key_bit_length_e len;
+               yaca_key_bit_length_e expected;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_DSA_PARAMS,
+                YACA_KEY_TYPE_DSA_PRIV,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DH_PARAMS,
+                YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_1024_160,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DH_PARAMS,
+                YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)(YACA_KEY_LENGTH_DH_GENERATOR_2 | 1024U),
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DH_PARAMS,
+                YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)(YACA_KEY_LENGTH_DH_GENERATOR_5 | 512U),
+                YACA_KEY_LENGTH_512BIT},
+               {YACA_KEY_TYPE_EC_PARAMS,
+                YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h params = YACA_KEY_NULL;
+               yaca_key_h key = YACA_KEY_NULL;
+               yaca_key_type_e key_type;
+               size_t key_length;
+
+               ret = yaca_key_generate(ka.type_params, ka.len, &params);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_get_type(params, &key_type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_get_bit_length(params, &key_length);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(key_type == ka.type_params);
+               BOOST_REQUIRE(key_length == ka.expected);
+
+               ret = yaca_key_generate_from_parameters(params, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_get_type(key, &key_type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_get_bit_length(key, &key_length);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(key_type == ka.type_key);
+               BOOST_REQUIRE(key_length == ka.expected);
+
+
+               yaca_key_destroy(params);
+               yaca_key_destroy(key);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T204__negative__key_generate_from_parameters, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, key_params = YACA_KEY_NULL;
+       yaca_key_h key = YACA_KEY_NULL;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT,
+                                                         &key_prv, &key_pub, &key_params);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_128BIT, &key_sym);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_generate_from_parameters(YACA_KEY_NULL, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate_from_parameters(key_prv, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate_from_parameters(key_pub, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate_from_parameters(key_sym, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_generate_from_parameters(key_params, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_params);
+       yaca_key_destroy(key_sym);
+}
+
+BOOST_FIXTURE_TEST_CASE(T205__positive__key_extract_public_parameters, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type_priv;
+               yaca_key_type_e type_pub;
+               yaca_key_type_e type_params;
+               yaca_key_bit_length_e len;
+               yaca_key_bit_length_e expected;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_RSA_PRIV,
+                YACA_KEY_TYPE_RSA_PUB,
+                YACA_INVALID_KEY_TYPE,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                YACA_KEY_TYPE_DSA_PUB,
+                YACA_KEY_TYPE_DSA_PARAMS,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DH_PRIV,
+                YACA_KEY_TYPE_DH_PUB,
+                YACA_KEY_TYPE_DH_PARAMS,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_2048_256,
+                YACA_KEY_LENGTH_2048BIT},
+               {YACA_KEY_TYPE_EC_PRIV,
+                YACA_KEY_TYPE_EC_PUB,
+                YACA_KEY_TYPE_EC_PARAMS,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h priv = YACA_KEY_NULL;
+               yaca_key_h pub = YACA_KEY_NULL;
+               yaca_key_type_e key_type;
+               size_t key_length;
+
+               ret = yaca_key_generate(ka.type_priv, ka.len, &priv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_extract_public(priv, &pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_get_type(pub, &key_type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_get_bit_length(pub, &key_length);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(key_type == ka.type_pub);
+               BOOST_REQUIRE(key_length == ka.expected);
+
+               if (ka.type_params != YACA_INVALID_KEY_TYPE) {
+                       yaca_key_h params = YACA_KEY_NULL;
+                       yaca_key_h key = YACA_KEY_NULL;
+
+                       ret = yaca_key_extract_parameters(pub, &params);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_key_get_type(params, &key_type);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       ret = yaca_key_get_bit_length(params, &key_length);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       BOOST_REQUIRE(key_type == ka.type_params);
+                       BOOST_REQUIRE(key_length == ka.expected);
+
+                       ret = yaca_key_generate_from_parameters(params, &key);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_key_get_type(key, &key_type);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       ret = yaca_key_get_bit_length(key, &key_length);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       BOOST_REQUIRE(key_type == ka.type_priv);
+                       BOOST_REQUIRE(key_length == ka.expected);
+
+                       yaca_key_destroy(params);
+                       yaca_key_destroy(key);
+               }
+
+               yaca_key_destroy(priv);
+               yaca_key_destroy(pub);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T206__negative__key_extract_public_parameters, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, key_params = YACA_KEY_NULL;
+       yaca_key_h key = YACA_KEY_NULL;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_prv, &key_pub, &key_params);
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_128BIT, &key_sym);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_extract_public(NULL, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_public(key_pub, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_public(key_params, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_public(key_sym, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_public(key_prv, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_parameters(NULL, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_parameters(key_params, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_parameters(key_sym, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_extract_parameters(key_prv, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_params);
+       yaca_key_destroy(key_sym);
+}
+
+BOOST_FIXTURE_TEST_CASE(T207__positive__key_import_export_symmetric, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+       };
+
+       struct format_args {
+               yaca_key_format_e format;
+               yaca_key_file_format_e file_format;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_512BIT},
+               {YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_UNSAFE_128BIT},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+
+               ret = yaca_key_generate(ka.type, ka.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               import_export(key, ka.type, ka.len, "",
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_RAW);
+
+               import_export(key, ka.type, ka.len, "",
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_BASE64);
+
+               yaca_key_destroy(key);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T208__negative__key_import_export_symmetric, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key = YACA_KEY_NULL, key_import = YACA_KEY_NULL;
+       yaca_key_type_e type;
+       size_t len;
+
+       char *data = NULL;
+       size_t data_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_export(YACA_KEY_NULL, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_INVALID_KEY_FORMAT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_PKCS8,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_INVALID_KEY_FILE_FORMAT, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, "password", &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, NULL, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, &data, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, NULL, &data, &data_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_import(YACA_INVALID_KEY_TYPE, "", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DH_PRIV, "", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DES, "", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "password", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", NULL, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", data, 0, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", data, data_len, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       /* should still be correct */
+       data[0] = (data[0] == 'A' ? 'Z' : 'A');
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(key_import, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(type == YACA_KEY_TYPE_SYMMETRIC);
+       ret = yaca_key_get_bit_length(key_import, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(len == YACA_KEY_LENGTH_256BIT);
+
+       yaca_key_destroy(key_import);
+
+       /* should be treated as raw */
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", data, data_len-1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(key_import, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(type == YACA_KEY_TYPE_SYMMETRIC);
+       ret = yaca_key_get_bit_length(key_import, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(len == 344);
+
+       yaca_key_destroy(key_import);
+
+       /* should be treated as raw */
+       data[0] = 10;
+       ret = yaca_key_import(YACA_KEY_TYPE_SYMMETRIC, "", data, data_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(key_import, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(type == YACA_KEY_TYPE_SYMMETRIC);
+       ret = yaca_key_get_bit_length(key_import, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(len == 352);
+
+       yaca_key_destroy(key_import);
+       yaca_key_destroy(key);
+       yaca_free(data);
+}
+
+BOOST_FIXTURE_TEST_CASE(T209__positive__key_import_export_asymmetric, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type_priv;
+               yaca_key_type_e type_pub;
+               yaca_key_type_e type_params;
+               yaca_key_bit_length_e len;
+               yaca_key_bit_length_e expected;
+       };
+
+       struct format_args {
+               yaca_key_format_e format;
+               yaca_key_file_format_e file_format;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_RSA_PRIV,
+                YACA_KEY_TYPE_RSA_PUB,
+                YACA_INVALID_KEY_TYPE,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                YACA_KEY_TYPE_DSA_PUB,
+                YACA_KEY_TYPE_DSA_PARAMS,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_EC_PRIV,
+                YACA_KEY_TYPE_EC_PUB,
+                YACA_KEY_TYPE_EC_PARAMS,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1},
+               {YACA_KEY_TYPE_DH_PRIV,
+                YACA_KEY_TYPE_DH_PUB,
+                YACA_KEY_TYPE_DH_PARAMS,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_1024_160,
+                YACA_KEY_LENGTH_1024BIT}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h key_priv = YACA_KEY_NULL;
+               yaca_key_h key_pub = YACA_KEY_NULL;
+
+               ret = yaca_key_generate(ka.type_priv, ka.len, &key_priv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               import_export(key_priv, ka.type_priv, ka.expected, NULL,
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER);
+
+               import_export(key_priv, ka.type_priv, ka.expected, NULL,
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM);
+
+               ret = yaca_key_extract_public(key_priv, &key_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               import_export(key_pub, ka.type_pub, ka.expected, "",
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER);
+
+               import_export(key_pub, ka.type_pub, ka.expected, "",
+                                         YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM);
+
+               if (ka.type_params != YACA_INVALID_KEY_TYPE) {
+                       yaca_key_h key_params = YACA_KEY_NULL;
+
+                       ret = yaca_key_extract_parameters(key_priv, &key_params);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       import_export(key_params, ka.type_params, ka.expected, NULL,
+                                                 YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_DER);
+
+                       import_export(key_params, ka.type_params, ka.expected, NULL,
+                                                 YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM);
+
+                       yaca_key_destroy(key_params);
+               }
+
+               yaca_key_destroy(key_priv);
+               yaca_key_destroy(key_pub);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T210__negative__key_import_export_asymmetric, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub;
+       yaca_key_h key_params = YACA_KEY_NULL, key_import = YACA_KEY_NULL;
+       char data_short[] = "abc";
+
+       char *data_pem = NULL, *data_der = NULL;
+       size_t data_pem_len, data_der_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub, &key_params);
+
+       ret = yaca_key_export(YACA_KEY_NULL, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_INVALID_KEY_FORMAT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_PKCS8,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_INVALID_KEY_FILE_FORMAT, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_BASE64, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_DER, "password", &data_der, &data_der_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", NULL, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", &data_pem, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_PEM, "", &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT,
+                                                 YACA_KEY_FILE_FORMAT_DER, "", &data_der, &data_der_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_import(YACA_INVALID_KEY_TYPE, "", data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_RSA_PRIV, "", data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PUB, "", data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PARAMS, "", data_der, data_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "password", data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "password", data_der, data_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", NULL, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_pem, 0, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_pem, data_pem_len, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_RSA_PRIV, "", data_short, strlen(data_short), &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       /* two bytes have to be removed to get EINVAL, one is not enough, it's probably newline */
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_pem, data_pem_len - 2, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_der, data_der_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_pem + 1, data_pem_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_der + 1, data_der_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       data_pem[30] = (data_pem[30] == 'a' ? 'z' : 'a');
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       data_der[0] = ~data_der[0];
+       data_der[1] = ~data_der[1];
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, "", data_der, data_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_params);
+       yaca_free(data_der);
+       yaca_free(data_pem);
+}
+
+BOOST_FIXTURE_TEST_CASE(T211__positive__key_import_export_encrypted, InitDebugFixture)
+{
+       static const char *PASSWORD = "ExamplE_PassworD";
+
+       struct default_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+       };
+
+       const std::vector<struct default_args> dargs = {
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT}
+       };
+
+       for (const auto &da: dargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+
+               ret = yaca_key_generate(da.type, da.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               import_export(key, da.type, da.len, PASSWORD,
+                                         YACA_KEY_FORMAT_DEFAULT,
+                                         YACA_KEY_FILE_FORMAT_PEM);
+
+               yaca_key_destroy(key);
+       }
+
+       struct pkcs8_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_key_bit_length_e expected;
+       };
+
+       const std::vector<struct pkcs8_args> pargs {
+               {YACA_KEY_TYPE_RSA_PRIV,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_DSA_PRIV,
+                YACA_KEY_LENGTH_1024BIT,
+                YACA_KEY_LENGTH_1024BIT},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1},
+               {YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_1024_160,
+                YACA_KEY_LENGTH_1024BIT}
+       };
+
+       for (const auto &pa: pargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+
+               ret = yaca_key_generate(pa.type, pa.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               import_export(key, pa.type, pa.expected, PASSWORD,
+                                         YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_DER);
+
+               import_export(key, pa.type, pa.expected, PASSWORD,
+                                         YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_PEM);
+
+               yaca_key_destroy(key);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T212__negative__key_import_export_encrypted, InitDebugFixture)
+{
+       static const char *PASSWORD = "ExamplE_PassworD";
+       static const char *WRONG_PASSWORD = "wRONg_pASSWORd";
+
+       int ret;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub;
+       yaca_key_h key_params = YACA_KEY_NULL, key_import = YACA_KEY_NULL;
+
+       char *data_pem = NULL, *data_pkcs8_pem = NULL, *data_pkcs8_der = NULL;
+       size_t data_pem_len, data_pkcs8_pem_len, data_pkcs8_der_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub, &key_params);
+
+       ret = yaca_key_export(key_pub, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM,
+                                                 PASSWORD, &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_params, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM,
+                                                 PASSWORD, &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_pub, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_PEM,
+                                                 PASSWORD, &data_pkcs8_pem, &data_pkcs8_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_params, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_DER,
+                                                 PASSWORD, &data_pkcs8_der, &data_pkcs8_der_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_PEM,
+                                                 NULL, &data_pkcs8_pem, &data_pkcs8_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_PKCS8, YACA_INVALID_KEY_FILE_FORMAT,
+                                                 PASSWORD, &data_pkcs8_pem, &data_pkcs8_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_DEFAULT, YACA_KEY_FILE_FORMAT_PEM,
+                                                 PASSWORD, &data_pem, &data_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_PEM,
+                                                 PASSWORD, &data_pkcs8_pem, &data_pkcs8_pem_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_export(key_prv, YACA_KEY_FORMAT_PKCS8, YACA_KEY_FILE_FORMAT_DER,
+                                                 PASSWORD, &data_pkcs8_der, &data_pkcs8_der_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PUB, PASSWORD,
+                                                 data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, NULL,
+                                                 data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, WRONG_PASSWORD,
+                                                 data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pem, data_pem_len - 2, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pem + 1, data_pem_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       data_pem[30] = (data_pem[30] == 'a' ? 'z' : 'a');
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pem, data_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PUB, PASSWORD,
+                                                 data_pkcs8_pem, data_pkcs8_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, NULL,
+                                                 data_pkcs8_pem, data_pkcs8_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, WRONG_PASSWORD,
+                                                 data_pkcs8_pem, data_pkcs8_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_pem, data_pkcs8_pem_len - 2, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_pem + 1, data_pkcs8_pem_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       data_pkcs8_pem[30] = (data_pkcs8_pem[30] == 'a' ? 'z' : 'a');
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_pem, data_pkcs8_pem_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PARAMS, PASSWORD,
+                                                 data_pkcs8_der, data_pkcs8_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, NULL,
+                                                 data_pkcs8_der, data_pkcs8_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, WRONG_PASSWORD,
+                                                 data_pkcs8_der, data_pkcs8_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PASSWORD);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_der, data_pkcs8_der_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_der+ 1, data_pkcs8_der_len - 1, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       data_pkcs8_der[0] = ~data_pkcs8_der[0];
+       data_pkcs8_der[1] = ~data_pkcs8_der[1];
+       ret = yaca_key_import(YACA_KEY_TYPE_DSA_PRIV, PASSWORD,
+                                                 data_pkcs8_der, data_pkcs8_der_len, &key_import);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_params);
+       yaca_free(data_pem);
+       yaca_free(data_pkcs8_pem);
+       yaca_free(data_pkcs8_der);
+}
+
+BOOST_FIXTURE_TEST_CASE(T213__positive__key_derive_dh, InitDebugFixture)
+{
+       struct key_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+       };
+
+       const std::vector<struct key_args> kargs = {
+               {YACA_KEY_TYPE_DH_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_DH_RFC_1024_160},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP384R1}
+       };
+
+       for (const auto &ka: kargs) {
+               int ret;
+               yaca_key_h priv1 = YACA_KEY_NULL, pub1 = YACA_KEY_NULL;
+               yaca_key_h priv2 = YACA_KEY_NULL, pub2 = YACA_KEY_NULL;
+               char *secret1 = NULL, *secret2 = NULL;
+               size_t secret1_len, secret2_len;
+
+               generate_asymmetric_keys(ka.type, ka.len, &priv1, &pub1);
+               generate_asymmetric_keys(ka.type, ka.len, &priv2, &pub2);
+
+               ret = yaca_key_derive_dh(priv1, pub2, &secret1, &secret1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_derive_dh(priv2, pub1, &secret2, &secret2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(secret1_len == secret2_len);
+               ret = yaca_memcmp(secret1, secret2, secret1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(priv1);
+               yaca_key_destroy(priv2);
+               yaca_key_destroy(pub1);
+               yaca_key_destroy(pub2);
+               yaca_free(secret1);
+               yaca_free(secret2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T214__negative__key_derive_dh, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h priv1 = YACA_KEY_NULL, pub1 = YACA_KEY_NULL;
+       yaca_key_h priv2 = YACA_KEY_NULL, pub2 = YACA_KEY_NULL;
+       char *secret = NULL;
+       size_t secret_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &priv1, &pub1);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &priv2, &pub2);
+
+       ret = yaca_key_derive_dh(YACA_KEY_NULL, pub2, &secret, &secret_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_dh(pub1, pub2, &secret, &secret_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_dh(priv1, YACA_KEY_NULL, &secret, &secret_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_dh(priv1, priv2, &secret, &secret_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_dh(priv1, pub2, NULL, &secret_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_dh(priv1, pub2, &secret, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(priv1);
+       yaca_key_destroy(priv2);
+       yaca_key_destroy(pub1);
+       yaca_key_destroy(pub2);
+}
+
+BOOST_FIXTURE_TEST_CASE(T215__positive__key_derive_kdf, InitDebugFixture)
+{
+       static const size_t SECRET_LEN = 128;
+       static const size_t MATERIAL_LEN = 256;
+
+       struct kdf_args {
+               yaca_kdf_e kdf;
+               yaca_digest_algorithm_e digest;
+       };
+
+       const std::vector<struct kdf_args> kargs = {
+               {YACA_KDF_X942, YACA_DIGEST_MD5},
+               {YACA_KDF_X942, YACA_DIGEST_SHA1},
+               {YACA_KDF_X942, YACA_DIGEST_SHA384},
+               {YACA_KDF_X962, YACA_DIGEST_MD5},
+               {YACA_KDF_X942, YACA_DIGEST_SHA1},
+               {YACA_KDF_X942, YACA_DIGEST_SHA256}
+       };
+
+       int ret;
+       char secret[SECRET_LEN];
+
+       ret = yaca_randomize_bytes(secret, SECRET_LEN);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       for (const auto &ka: kargs) {
+               char *key_material1 = NULL, *key_material2 = NULL;
+
+               ret = yaca_key_derive_kdf(ka.kdf, ka.digest, secret, SECRET_LEN,
+                                                                 NULL, 0, MATERIAL_LEN, &key_material1);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_derive_kdf(ka.kdf, ka.digest, secret, SECRET_LEN,
+                                                                 NULL, 0, MATERIAL_LEN, &key_material2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_memcmp(key_material1, key_material2, MATERIAL_LEN);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_free(key_material1);
+               yaca_free(key_material2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T216__negative__key_derive_kdf, InitDebugFixture)
+{
+       static const size_t SECRET_LEN = 128;
+       static const size_t MATERIAL_LEN = 256;
+
+       int ret;
+       char secret[SECRET_LEN];
+       char *key_material = NULL;
+
+       ret = yaca_randomize_bytes(secret, SECRET_LEN);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_derive_kdf(YACA_INVALID_KDF, YACA_DIGEST_MD5, secret, SECRET_LEN,
+                                                         NULL, 0, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_INVALID_DIGEST_ALGORITHM, secret, SECRET_LEN,
+                                                         NULL, 0, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, NULL, SECRET_LEN,
+                                                         NULL, 0, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, secret, 0,
+                                                         NULL, 0, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, secret, SECRET_LEN,
+                                                         "test", 0, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, secret, SECRET_LEN,
+                                                         NULL, 10, MATERIAL_LEN, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, secret, SECRET_LEN,
+                                                         NULL, 0, 0, &key_material);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_kdf(YACA_KDF_X942, YACA_DIGEST_MD5, secret, SECRET_LEN,
+                                                         NULL, 0, MATERIAL_LEN, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T217__positive__key_derive_pbkdf2, InitDebugFixture)
+{
+       static const char *PASSWORD = "Password_ExamplE";
+       static const size_t SALT_LEN = 64;
+
+       struct pbkdf2_args {
+               yaca_digest_algorithm_e digest;
+               size_t iter;
+               size_t bit_len;
+       };
+
+       const std::vector<struct pbkdf2_args> pargs = {
+               {YACA_DIGEST_MD5, 1, 256},
+               {YACA_DIGEST_SHA256, 10, 256},
+               {YACA_DIGEST_SHA1, 15, 512},
+               {YACA_DIGEST_SHA224, 33, 128},
+               {YACA_DIGEST_SHA512, 50, 512}
+       };
+
+       int ret;
+       char salt[SALT_LEN];
+
+       ret = yaca_randomize_bytes(salt, SALT_LEN);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       for (const auto &pa: pargs) {
+               yaca_key_h key1 = YACA_KEY_NULL, key2 = YACA_KEY_NULL;
+               yaca_key_type_e type;
+               size_t len;
+
+               ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, pa.iter,
+                                                                        pa.digest, pa.bit_len, &key1);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, pa.iter,
+                                                                        pa.digest, pa.bit_len, &key2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_get_type(key1, &type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(type == YACA_KEY_TYPE_SYMMETRIC);
+               ret = yaca_key_get_bit_length(key1, &len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(len == pa.bit_len);
+
+               ret = yaca_key_get_type(key2, &type);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(type == YACA_KEY_TYPE_SYMMETRIC);
+               ret = yaca_key_get_bit_length(key2, &len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(len == pa.bit_len);
+
+               assert_keys_identical(key1, key2);
+
+               yaca_key_destroy(key1);
+               yaca_key_destroy(key2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T218__negative__key_derive_pbkdf2, InitDebugFixture)
+{
+       static const char *PASSWORD = "Password_ExamplE";
+       static const size_t SALT_LEN = 64;
+
+       int ret;
+       char salt[SALT_LEN];
+       yaca_key_h key = YACA_KEY_NULL;
+
+       ret = yaca_randomize_bytes(salt, SALT_LEN);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_derive_pbkdf2(NULL, salt, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, NULL, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, 0, 10,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 0,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, INT_MAX + 1UL,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 10,
+                                                                YACA_INVALID_DIGEST_ALGORITHM, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, 0, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, 1, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, 127, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_derive_pbkdf2(PASSWORD, salt, SALT_LEN, 10,
+                                                                YACA_DIGEST_SHA1, YACA_KEY_LENGTH_256BIT, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T219__positive__import_x509_cert, InitDebugFixture)
+{
+       static const char data_pem[] = "-----BEGIN CERTIFICATE-----\n\
+MIIC9jCCAl+gAwIBAgIUaWM7DVy/evvsrKz8gkz3qWZKw7EwDQYJKoZIhvcNAQEL\n\
+BQAwgYwxCzAJBgNVBAYTAlBMMRQwEgYDVQQIDAtNYXpvd2llY2tpZTERMA8GA1UE\n\
+BwwIV2Fyc3phd2ExEDAOBgNVBAoMB1NhbXN1bmcxCzAJBgNVBAsMAklUMRQwEgYD\n\
+VQQDDAtzYW1zdW5nLmNvbTEfMB0GCSqGSIb3DQEJARYQbm9uZUBzYW1zdW5nLmNv\n\
+bTAeFw0yMDA0MDkxNzUzMDlaFw0yNTA0MDgxNzUzMDlaMIGMMQswCQYDVQQGEwJQ\n\
+TDEUMBIGA1UECAwLTWF6b3dpZWNraWUxETAPBgNVBAcMCFdhcnN6YXdhMRAwDgYD\n\
+VQQKDAdTYW1zdW5nMQswCQYDVQQLDAJJVDEUMBIGA1UEAwwLc2Ftc3VuZy5jb20x\n\
+HzAdBgkqhkiG9w0BCQEWEG5vbmVAc2Ftc3VuZy5jb20wgZ8wDQYJKoZIhvcNAQEB\n\
+BQADgY0AMIGJAoGBAMrx4VdcBEWSXdOa7nJr6Vh53TDfnqhgOGRUC8c+kGUu45Cp\n\
+hcGU7q44zfqvEdgkVBK+Y6GBMrbB0TALo2zK4RVDIgTc8UskbiBjiP4cHB+Zl460\n\
+kU/0vKZPWt7yWq9g87lppEr/f0RTGrKkkcVadCxmKILr4ZtS9563xXH+kKAlAgMB\n\
+AAGjUzBRMB0GA1UdDgQWBBQBroKxSi+l6RqOD5jQGRYyoM0I1jAfBgNVHSMEGDAW\n\
+gBQBroKxSi+l6RqOD5jQGRYyoM0I1jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n\
+DQEBCwUAA4GBAC1f+n4ly876nTXMjdINH8qmxrHOH55vt7v1KYWqCVFSJbqtQMlT\n\
+E9+bqRGN2LpzMBkDdNkGSrCesI1l/FUStjqdpBGMi1fqFDNDyBXkLJDH5HAMR3ei\n\
+hajHIasdGWcAfj+Cyuk1KcTIEkBfdYR6a8C4g04Vbg6M0qEjFl5UTMwm\n\
+-----END CERTIFICATE-----";
+
+       /* THIS CHUNK OF BYTES IS AUTOMATICALLY GENERATED */
+       static const unsigned char data_der[] = {
+               0x30, 0x82, 0x02, 0xf6, 0x30, 0x82, 0x02, 0x5f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x14, 0x69,
+               0x63, 0x3b, 0x0d, 0x5c, 0xbf, 0x7a, 0xfb, 0xec, 0xac, 0xac, 0xfc, 0x82, 0x4c, 0xf7, 0xa9, 0x66,
+               0x4a, 0xc3, 0xb1, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
+               0x05, 0x00, 0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+               0x50, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b, 0x4d, 0x61, 0x7a,
+               0x6f, 0x77, 0x69, 0x65, 0x63, 0x6b, 0x69, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
+               0x07, 0x0c, 0x08, 0x57, 0x61, 0x72, 0x73, 0x7a, 0x61, 0x77, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
+               0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x31, 0x0b, 0x30,
+               0x09, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x49, 0x54, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03,
+               0x55, 0x04, 0x03, 0x0c, 0x0b, 0x73, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x2e, 0x63, 0x6f, 0x6d,
+               0x31, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16,
+               0x10, 0x6e, 0x6f, 0x6e, 0x65, 0x40, 0x73, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x2e, 0x63, 0x6f,
+               0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x34, 0x30, 0x39, 0x31, 0x37, 0x35, 0x33, 0x30,
+               0x39, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x34, 0x30, 0x38, 0x31, 0x37, 0x35, 0x33, 0x30, 0x39,
+               0x5a, 0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x50,
+               0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0b, 0x4d, 0x61, 0x7a, 0x6f,
+               0x77, 0x69, 0x65, 0x63, 0x6b, 0x69, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07,
+               0x0c, 0x08, 0x57, 0x61, 0x72, 0x73, 0x7a, 0x61, 0x77, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
+               0x55, 0x04, 0x0a, 0x0c, 0x07, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x31, 0x0b, 0x30, 0x09,
+               0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x49, 0x54, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
+               0x04, 0x03, 0x0c, 0x0b, 0x73, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
+               0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10,
+               0x6e, 0x6f, 0x6e, 0x65, 0x40, 0x73, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x2e, 0x63, 0x6f, 0x6d,
+               0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+               0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xca, 0xf1, 0xe1,
+               0x57, 0x5c, 0x04, 0x45, 0x92, 0x5d, 0xd3, 0x9a, 0xee, 0x72, 0x6b, 0xe9, 0x58, 0x79, 0xdd, 0x30,
+               0xdf, 0x9e, 0xa8, 0x60, 0x38, 0x64, 0x54, 0x0b, 0xc7, 0x3e, 0x90, 0x65, 0x2e, 0xe3, 0x90, 0xa9,
+               0x85, 0xc1, 0x94, 0xee, 0xae, 0x38, 0xcd, 0xfa, 0xaf, 0x11, 0xd8, 0x24, 0x54, 0x12, 0xbe, 0x63,
+               0xa1, 0x81, 0x32, 0xb6, 0xc1, 0xd1, 0x30, 0x0b, 0xa3, 0x6c, 0xca, 0xe1, 0x15, 0x43, 0x22, 0x04,
+               0xdc, 0xf1, 0x4b, 0x24, 0x6e, 0x20, 0x63, 0x88, 0xfe, 0x1c, 0x1c, 0x1f, 0x99, 0x97, 0x8e, 0xb4,
+               0x91, 0x4f, 0xf4, 0xbc, 0xa6, 0x4f, 0x5a, 0xde, 0xf2, 0x5a, 0xaf, 0x60, 0xf3, 0xb9, 0x69, 0xa4,
+               0x4a, 0xff, 0x7f, 0x44, 0x53, 0x1a, 0xb2, 0xa4, 0x91, 0xc5, 0x5a, 0x74, 0x2c, 0x66, 0x28, 0x82,
+               0xeb, 0xe1, 0x9b, 0x52, 0xf7, 0x9e, 0xb7, 0xc5, 0x71, 0xfe, 0x90, 0xa0, 0x25, 0x02, 0x03, 0x01,
+               0x00, 0x01, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
+               0x14, 0x01, 0xae, 0x82, 0xb1, 0x4a, 0x2f, 0xa5, 0xe9, 0x1a, 0x8e, 0x0f, 0x98, 0xd0, 0x19, 0x16,
+               0x32, 0xa0, 0xcd, 0x08, 0xd6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
+               0x80, 0x14, 0x01, 0xae, 0x82, 0xb1, 0x4a, 0x2f, 0xa5, 0xe9, 0x1a, 0x8e, 0x0f, 0x98, 0xd0, 0x19,
+               0x16, 0x32, 0xa0, 0xcd, 0x08, 0xd6, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
+               0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+               0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x2d, 0x5f, 0xfa, 0x7e, 0x25, 0xcb,
+               0xce, 0xfa, 0x9d, 0x35, 0xcc, 0x8d, 0xd2, 0x0d, 0x1f, 0xca, 0xa6, 0xc6, 0xb1, 0xce, 0x1f, 0x9e,
+               0x6f, 0xb7, 0xbb, 0xf5, 0x29, 0x85, 0xaa, 0x09, 0x51, 0x52, 0x25, 0xba, 0xad, 0x40, 0xc9, 0x53,
+               0x13, 0xdf, 0x9b, 0xa9, 0x11, 0x8d, 0xd8, 0xba, 0x73, 0x30, 0x19, 0x03, 0x74, 0xd9, 0x06, 0x4a,
+               0xb0, 0x9e, 0xb0, 0x8d, 0x65, 0xfc, 0x55, 0x12, 0xb6, 0x3a, 0x9d, 0xa4, 0x11, 0x8c, 0x8b, 0x57,
+               0xea, 0x14, 0x33, 0x43, 0xc8, 0x15, 0xe4, 0x2c, 0x90, 0xc7, 0xe4, 0x70, 0x0c, 0x47, 0x77, 0xa2,
+               0x85, 0xa8, 0xc7, 0x21, 0xab, 0x1d, 0x19, 0x67, 0x00, 0x7e, 0x3f, 0x82, 0xca, 0xe9, 0x35, 0x29,
+               0xc4, 0xc8, 0x12, 0x40, 0x5f, 0x75, 0x84, 0x7a, 0x6b, 0xc0, 0xb8, 0x83, 0x4e, 0x15, 0x6e, 0x0e,
+               0x8c, 0xd2, 0xa1, 0x23, 0x16, 0x5e, 0x54, 0x4c, 0xcc, 0x26
+       };
+
+       int ret;
+       yaca_key_h key_pem = YACA_KEY_NULL, key_der = YACA_KEY_NULL;
+       yaca_key_type_e type;
+       size_t len;
+
+       ret = yaca_key_import(YACA_KEY_TYPE_RSA_PUB, NULL, data_pem,
+                                                 sizeof(data_pem), &key_pem);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(key_pem, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(type == YACA_KEY_TYPE_RSA_PUB);
+
+       ret = yaca_key_get_bit_length(key_pem, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(len == YACA_KEY_LENGTH_1024BIT);
+
+       ret = yaca_key_import(YACA_KEY_TYPE_RSA_PUB, NULL, (char*)data_der,
+                                                 sizeof(data_der), &key_der);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(key_der, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(type == YACA_KEY_TYPE_RSA_PUB);
+
+       ret = yaca_key_get_bit_length(key_der, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       BOOST_REQUIRE(len == YACA_KEY_LENGTH_1024BIT);
+
+       assert_keys_identical(key_pem, key_der);
+
+       yaca_key_destroy(key_pem);
+       yaca_key_destroy(key_der);
+}
+
+BOOST_FIXTURE_TEST_CASE(T220__negative__key_get, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key = YACA_KEY_NULL;
+       yaca_key_type_e type;
+       size_t len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_key_get_type(YACA_KEY_NULL, &type);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_get_bit_length(YACA_KEY_NULL, &len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_get_type(key, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_key_get_bit_length(key, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_rsa.cpp b/tests/test_rsa.cpp
new file mode 100644 (file)
index 0000000..0f9e095
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_rsa.c
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   RSA API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_rsa.h>
+#include <yaca_key.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_RSA)
+
+BOOST_FIXTURE_TEST_CASE(T401__positive__private_encrypt, InitDebugFixture)
+{
+       struct rsa_args {
+               yaca_padding_e pad;
+               yaca_key_bit_length_e bit_len;
+               size_t shorter;
+       };
+
+       const std::vector<struct rsa_args> rargs = {
+               {YACA_PADDING_NONE,         YACA_KEY_LENGTH_512BIT,   0},
+               {YACA_PADDING_NONE,         YACA_KEY_LENGTH_2048BIT,  0},
+               {YACA_PADDING_PKCS1,        YACA_KEY_LENGTH_512BIT,  11},
+               {YACA_PADDING_PKCS1,        YACA_KEY_LENGTH_4096BIT, 11},
+       };
+
+       for (const auto &ra: rargs) {
+               int ret;
+               yaca_key_h rsa_prv = YACA_KEY_NULL, rsa_pub = YACA_KEY_NULL;
+               size_t input_len = ra.bit_len / 8 - ra.shorter;
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, ra.bit_len, &rsa_prv, &rsa_pub);
+
+               ret = yaca_rsa_private_encrypt(ra.pad, rsa_prv, INPUT_DATA, input_len,
+                                                                          &encrypted, &encrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_rsa_public_decrypt(ra.pad, rsa_pub, encrypted, encrypted_len,
+                                                                         &decrypted, &decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(decrypted_len == input_len);
+               ret = yaca_memcmp(decrypted, INPUT_DATA, input_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(rsa_prv);
+               yaca_key_destroy(rsa_pub);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+
+       /* Empty input, must use padding */
+       for (const auto &ra: rargs) {
+               if (ra.pad == YACA_PADDING_NONE)
+                       continue;
+
+               int ret;
+               yaca_key_h rsa_prv = YACA_KEY_NULL, rsa_pub = YACA_KEY_NULL;
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, ra.bit_len, &rsa_prv, &rsa_pub);
+
+               ret = yaca_rsa_private_encrypt(ra.pad, rsa_prv, NULL, 0,
+                                                                          &encrypted, &encrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_rsa_public_decrypt(ra.pad, rsa_pub, encrypted, encrypted_len,
+                                                                         &decrypted, &decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(decrypted == NULL);
+               BOOST_REQUIRE(decrypted_len == 0);
+
+               yaca_key_destroy(rsa_prv);
+               yaca_key_destroy(rsa_pub);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T402__negative__private_encrypt, InitDebugFixture)
+{
+       int ret;
+       size_t bit_len = YACA_KEY_LENGTH_1024BIT;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_prv2 = YACA_KEY_NULL, key_pub2 = YACA_KEY_NULL;
+       yaca_key_h key_dsa = YACA_KEY_NULL, key_ec = YACA_KEY_NULL;
+       size_t input_len = bit_len / 8;
+       size_t input_len_pkcs1 = bit_len / 8 - 11;
+       char *encrypted = NULL, *encrypted_pkcs1 = NULL, *decrypted = NULL;
+       size_t encrypted_len, encrypted_pkcs1_len, decrypted_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, bit_len, &key_prv, &key_pub);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, bit_len, &key_prv2, &key_pub2);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, bit_len, &key_dsa);
+       generate_asymmetric_keys(YACA_KEY_TYPE_EC_PRIV, YACA_KEY_LENGTH_EC_PRIME256V1, &key_ec);
+
+       ret = yaca_rsa_private_encrypt(YACA_INVALID_PADDING, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_X931, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_PKCS1_OAEP, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, YACA_KEY_NULL,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_ec,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_dsa,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  NULL, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, 0,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len + 1,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len - 1,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len - 8,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  NULL, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_PKCS1, key_prv,
+                                                                  INPUT_DATA, input_len_pkcs1 + 1,
+                                                                  &encrypted_pkcs1, &encrypted_pkcs1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                  INPUT_DATA, input_len,
+                                                                  &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_rsa_private_encrypt(YACA_PADDING_PKCS1, key_prv,
+                                                                  INPUT_DATA, input_len_pkcs1,
+                                                                  &encrypted_pkcs1, &encrypted_pkcs1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_rsa_public_decrypt(YACA_INVALID_PADDING, key_pub,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1_SSLV23, key_pub,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1, key_pub,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, YACA_KEY_NULL,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_prv,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_ec,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_dsa,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_pub,
+                                                                 NULL, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_pub,
+                                                                 encrypted, 0,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_pub,
+                                                                 encrypted, encrypted_len,
+                                                                 NULL, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_NONE, key_pub,
+                                                                 encrypted, encrypted_len,
+                                                                 &decrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1_PSS, key_pub,
+                                                                 encrypted_pkcs1, encrypted_pkcs1_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_X931, key_pub,
+                                                                 encrypted_pkcs1, encrypted_pkcs1_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1, key_pub2,
+                                                                 encrypted_pkcs1, encrypted_pkcs1_len,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1, key_pub,
+                                                                 encrypted_pkcs1, encrypted_pkcs1_len - 1,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_decrypt(YACA_PADDING_PKCS1, key_pub,
+                                                                 encrypted_pkcs1 + 1, encrypted_pkcs1_len - 1,
+                                                                 &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_prv2);
+       yaca_key_destroy(key_pub2);
+       yaca_key_destroy(key_dsa);
+       yaca_key_destroy(key_ec);
+       yaca_free(encrypted);
+       yaca_free(encrypted_pkcs1);
+}
+
+BOOST_FIXTURE_TEST_CASE(T403__positive__public_encrypt, InitDebugFixture)
+{
+       struct rsa_args {
+               yaca_padding_e pad;
+               yaca_key_bit_length_e bit_len;
+               size_t shorter;
+       };
+
+       const std::vector<struct rsa_args> rargs = {
+               {YACA_PADDING_NONE,         YACA_KEY_LENGTH_512BIT,   0},
+               {YACA_PADDING_PKCS1,        YACA_KEY_LENGTH_1024BIT, 11},
+               {YACA_PADDING_PKCS1_OAEP,   YACA_KEY_LENGTH_2048BIT, 42},
+       };
+
+       for (const auto &ra: rargs) {
+               int ret;
+               yaca_key_h rsa_prv = YACA_KEY_NULL, rsa_pub = YACA_KEY_NULL;
+               size_t input_len = ra.bit_len / 8 - ra.shorter;
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, ra.bit_len, &rsa_prv, &rsa_pub);
+
+               ret = yaca_rsa_public_encrypt(ra.pad, rsa_pub, INPUT_DATA, input_len,
+                                                                         &encrypted, &encrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_rsa_private_decrypt(ra.pad, rsa_prv, encrypted, encrypted_len,
+                                                                          &decrypted, &decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(decrypted_len == input_len);
+               ret = yaca_memcmp(decrypted, INPUT_DATA, input_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(rsa_prv);
+               yaca_key_destroy(rsa_pub);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+
+       /* Empty input, must use padding */
+       for (const auto &ra: rargs) {
+               if (ra.pad == YACA_PADDING_NONE)
+                       continue;
+
+               int ret;
+               yaca_key_h rsa_prv = YACA_KEY_NULL, rsa_pub = YACA_KEY_NULL;
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, ra.bit_len, &rsa_prv, &rsa_pub);
+
+               ret = yaca_rsa_public_encrypt(ra.pad, rsa_pub, NULL, 0,
+                                                                         &encrypted, &encrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_rsa_private_decrypt(ra.pad, rsa_prv, encrypted, encrypted_len,
+                                                                          &decrypted, &decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(decrypted_len == 0);
+               BOOST_REQUIRE(decrypted == NULL);
+
+               yaca_key_destroy(rsa_prv);
+               yaca_key_destroy(rsa_pub);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T404__negative__public_encrypt, InitDebugFixture)
+{
+       int ret;
+       size_t bit_len = YACA_KEY_LENGTH_1024BIT;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_prv2 = YACA_KEY_NULL, key_pub2 = YACA_KEY_NULL;
+       yaca_key_h key_dsa = YACA_KEY_NULL, key_ec = YACA_KEY_NULL;
+       size_t input_len = bit_len / 8;
+       size_t input_len_pkcs1 = bit_len / 8 - 11;
+       size_t input_len_pkcs1_oaep = bit_len / 8 - 42;
+       size_t input_len_pkcs1_sslv23 = bit_len / 8 - 11;
+       char *encrypted = NULL, *encrypted_pkcs1 = NULL;
+       char *encrypted_pkcs1_oaep = NULL, *encrypted_pkcs1_sslv23 = NULL;
+       char *decrypted = NULL;
+       size_t encrypted_len, encrypted_pkcs1_len, encrypted_pkcs1_oaep_len;
+       size_t encrypted_pkcs1_sslv23_len, decrypted_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, bit_len, &key_prv, &key_pub);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, bit_len, &key_prv2, &key_pub2);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, bit_len, &key_dsa);
+       generate_asymmetric_keys(YACA_KEY_TYPE_EC_PRIV, YACA_KEY_LENGTH_EC_PRIME256V1, &key_ec);
+
+       ret = yaca_rsa_public_encrypt(YACA_INVALID_PADDING, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_X931, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1_PSS, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, YACA_KEY_NULL,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_prv,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_ec,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_dsa,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 NULL, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, 0,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len + 1,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len - 1,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len - 8,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 NULL, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1 + 1,
+                                                                 &encrypted_pkcs1, &encrypted_pkcs1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1_OAEP, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1_oaep + 1,
+                                                                 &encrypted_pkcs1_oaep, &encrypted_pkcs1_oaep_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1_SSLV23, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1_sslv23 + 1,
+                                                                 &encrypted_pkcs1_sslv23, &encrypted_pkcs1_sslv23_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_NONE, key_pub,
+                                                                 INPUT_DATA, input_len,
+                                                                 &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1,
+                                                                 &encrypted_pkcs1, &encrypted_pkcs1_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1_OAEP, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1_oaep,
+                                                                 &encrypted_pkcs1_oaep, &encrypted_pkcs1_oaep_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_rsa_public_encrypt(YACA_PADDING_PKCS1_SSLV23, key_pub,
+                                                                 INPUT_DATA, input_len_pkcs1_sslv23,
+                                                                 &encrypted_pkcs1_sslv23, &encrypted_pkcs1_sslv23_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_rsa_private_decrypt(YACA_INVALID_PADDING, key_prv,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_X931, key_prv,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1, key_prv,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, YACA_KEY_NULL,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_pub,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_ec,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_dsa,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_prv,
+                                                                  NULL, encrypted_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_prv,
+                                                                  encrypted, 0,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_prv,
+                                                                  encrypted, encrypted_len,
+                                                                  NULL, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_NONE, key_prv,
+                                                                  encrypted, encrypted_len,
+                                                                  &decrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1_PSS, key_prv,
+                                                                  encrypted_pkcs1, encrypted_pkcs1_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1, key_prv,
+                                                                  encrypted_pkcs1, encrypted_pkcs1_len - 1,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1, key_prv,
+                                                                  encrypted_pkcs1_oaep, encrypted_pkcs1_oaep_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1_SSLV23, key_prv,
+                                                                  encrypted_pkcs1_oaep, encrypted_pkcs1_oaep_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1_OAEP, key_prv,
+                                                                  encrypted_pkcs1_oaep, encrypted_pkcs1_oaep_len - 1,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1_OAEP, key_prv,
+                                                                  encrypted_pkcs1_sslv23, encrypted_pkcs1_sslv23_len,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_rsa_private_decrypt(YACA_PADDING_PKCS1_SSLV23, key_prv,
+                                                                  encrypted_pkcs1_sslv23, encrypted_pkcs1_sslv23_len - 1,
+                                                                  &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_prv2);
+       yaca_key_destroy(key_pub2);
+       yaca_key_destroy(key_dsa);
+       yaca_key_destroy(key_ec);
+       yaca_free(encrypted);
+       yaca_free(encrypted_pkcs1);
+       yaca_free(encrypted_pkcs1_oaep);
+       yaca_free(encrypted_pkcs1_sslv23);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_seal.cpp b/tests/test_seal.cpp
new file mode 100644 (file)
index 0000000..63f78b2
--- /dev/null
@@ -0,0 +1,1683 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_seal.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Seal API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_seal.h>
+#include <yaca_key.h>
+#include <yaca_encrypt.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_SEAL)
+
+BOOST_FIXTURE_TEST_CASE(T701__positive__seal_open, InitDebugFixture)
+{
+       struct seal_args {
+               yaca_encrypt_algorithm_e algo;
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+               yaca_padding_e padding;
+               size_t split;
+       };
+
+       const std::vector<seal_args> sargs = {
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_INVALID_PADDING, 16},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_PADDING_NONE,     8},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  128, YACA_PADDING_PKCS7,   11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  128, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 128, YACA_INVALID_PADDING, 13},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 128, YACA_INVALID_PADDING,  4},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  128, YACA_INVALID_PADDING, 66},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_INVALID_PADDING,  3},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  128, YACA_PADDING_PKCS7,   34},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  128, YACA_INVALID_PADDING, 27},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_PADDING_NONE,    12},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  192, YACA_PADDING_PKCS7,   11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  192, YACA_INVALID_PADDING, 31},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 192, YACA_INVALID_PADDING, 17},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 192, YACA_INVALID_PADDING,  2},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  192, YACA_INVALID_PADDING,  1},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_PADDING_NONE,    15},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  192, YACA_PADDING_PKCS7,   33},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  192, YACA_INVALID_PADDING, 44},
+
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_INVALID_PADDING, 10},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_AES, YACA_BCM_CBC,  256, YACA_PADDING_PKCS7,   23},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB,  256, YACA_INVALID_PADDING, 17},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB1, 256, YACA_INVALID_PADDING, 23},
+               {YACA_ENCRYPT_AES, YACA_BCM_CFB8, 256, YACA_INVALID_PADDING, 29},
+               {YACA_ENCRYPT_AES, YACA_BCM_CTR,  256, YACA_INVALID_PADDING, 21},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_PADDING_NONE,     3},
+               {YACA_ENCRYPT_AES, YACA_BCM_ECB,  256, YACA_PADDING_PKCS7,   15},
+               {YACA_ENCRYPT_AES, YACA_BCM_OFB,  256, YACA_INVALID_PADDING, 13},
+
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_INVALID_PADDING, 31},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_PADDING_NONE,    22},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CBC,  64, YACA_PADDING_PKCS7,   39},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB,  64, YACA_INVALID_PADDING, 24},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB1, 64, YACA_INVALID_PADDING, 11},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_CFB8, 64, YACA_INVALID_PADDING, 22},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_INVALID_PADDING,  7},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_PADDING_NONE,    19},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_ECB,  64, YACA_PADDING_PKCS7,    9},
+               {YACA_ENCRYPT_UNSAFE_DES, YACA_BCM_OFB,  64, YACA_INVALID_PADDING,  2},
+
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_INVALID_PADDING, 16},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_PADDING_NONE,    25},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CBC, 128, YACA_PADDING_PKCS7,   26},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_CFB, 128, YACA_INVALID_PADDING, 23},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_INVALID_PADDING, 13},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_PADDING_NONE,    10},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_ECB, 128, YACA_PADDING_PKCS7,   29},
+               {YACA_ENCRYPT_UNSAFE_3DES_2TDEA, YACA_BCM_OFB, 128, YACA_INVALID_PADDING, 32},
+
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_INVALID_PADDING, 39},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_PADDING_NONE,    29},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC,  192, YACA_PADDING_PKCS7,   19},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB,  192, YACA_INVALID_PADDING,  9},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB1, 192, YACA_INVALID_PADDING, 44},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CFB8, 192, YACA_INVALID_PADDING, 33},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_INVALID_PADDING, 22},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_PADDING_NONE,    11},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_ECB,  192, YACA_PADDING_PKCS7,   13},
+               {YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_OFB,  192, YACA_INVALID_PADDING,  1},
+
+               {YACA_ENCRYPT_UNSAFE_RC4, YACA_BCM_NONE, 256, YACA_INVALID_PADDING, 17},
+
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_INVALID_PADDING,  3},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_PADDING_NONE,    24},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CBC, 128, YACA_PADDING_PKCS7,   21},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_CFB, 128, YACA_INVALID_PADDING, 19},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_INVALID_PADDING,  7},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_PADDING_NONE,     6},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_ECB, 128, YACA_PADDING_PKCS7,   18},
+               {YACA_ENCRYPT_CAST5, YACA_BCM_OFB, 128, YACA_INVALID_PADDING,  2},
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+               yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+               /* SEAL */
+               {
+                       ret = yaca_seal_initialize(&ctx, key_pub, sa.algo, sa.bcm,
+                                                                          sa.key_bit_len, &key_sym, &iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, sa.split, encrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, sa.split,
+                                                        yaca_seal_update);
+
+                       if (sa.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &sa.padding,
+                                                                                               sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* OPEN */
+               {
+                       ret = yaca_open_initialize(&ctx, key_prv, sa.algo, sa.bcm,
+                                                                          sa.key_bit_len, key_sym, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.padding != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &sa.padding,
+                                                                                               sizeof(yaca_padding_e));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, encrypted_len, sa.split, decrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, sa.split,
+                                                        yaca_open_update);
+
+                       ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key_prv);
+               yaca_key_destroy(key_pub);
+               yaca_key_destroy(key_sym);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T702__negative__seal_open, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL, ctx_encrypt = YACA_CONTEXT_NULL;
+       yaca_key_h key_rsa_prv = YACA_KEY_NULL, key_rsa_pub = YACA_KEY_NULL;
+       yaca_key_h key_rsa_prv2 = YACA_KEY_NULL, key_rsa_pub2 = YACA_KEY_NULL;
+       yaca_key_h key_dsa_prv = YACA_KEY_NULL, key_dsa_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, key_sym2 = YACA_KEY_NULL;
+       yaca_key_h iv = YACA_KEY_NULL, iv2 = YACA_KEY_NULL;
+       yaca_padding_e pad_pkcs7 = YACA_PADDING_PKCS7;
+       yaca_padding_e pad_invalid = YACA_PADDING_X931;
+       size_t len = 128;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len = 0, decrypted_len = 0;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key_sym2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, YACA_KEY_LENGTH_IV_128BIT, &iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_encrypt_initialize(&ctx_encrypt, YACA_ENCRYPT_AES, YACA_BCM_CBC, key_sym2, iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_rsa_prv,  &key_rsa_pub);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_rsa_prv2, &key_rsa_pub2);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_dsa_prv,  &key_dsa_pub);
+
+       /* get an encrypted key_sym2 */
+       yaca_key_destroy(key_sym2);
+       key_sym2 = YACA_KEY_NULL;
+       ret = yaca_seal_initialize(&ctx, key_rsa_pub2, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                          YACA_KEY_LENGTH_256BIT, &key_sym2, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       yaca_context_destroy(ctx);
+       ctx = YACA_CONTEXT_NULL;
+       yaca_key_destroy(iv);
+       iv = YACA_KEY_NULL;
+
+       /* SEAL */
+       {
+               ret = yaca_seal_initialize(NULL, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, YACA_KEY_NULL, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_dsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_dsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_sym2, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  257, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, NULL, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CTR,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, INPUT_DATA_SIZE, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_seal_update(YACA_CONTEXT_NULL, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx_encrypt, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, 0, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &pad_pkcs7,
+                                                                               sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_finalize(YACA_CONTEXT_NULL, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx_encrypt, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING, &pad_pkcs7,
+                                                                               sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* OPEN */
+       {
+               ret = yaca_open_initialize(NULL, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_dsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_dsa_pub, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_sym2, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_192BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, YACA_KEY_NULL, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_rsa_prv, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, iv, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, key_sym2);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, encrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(YACA_CONTEXT_NULL, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx_encrypt, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, 0, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(YACA_CONTEXT_NULL, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx_encrypt, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, wrong asym key */
+       {
+               ret = yaca_open_initialize(&ctx, key_rsa_prv2, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+       }
+
+       /* OPEN, wrong BCM */
+       {
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_ECB,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, wrong symmetric key */
+       {
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym2, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+       }
+
+       /* OPEN, broken the end of ciphertext */
+       {
+               encrypted[encrypted_len - 1] = ~encrypted[encrypted_len - 1];
+               encrypted[encrypted_len - 2] = ~encrypted[encrypted_len - 2];
+
+               ret = yaca_open_initialize(&ctx, key_rsa_prv, YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_pkcs7, sizeof(yaca_padding_e));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key_rsa_prv);
+       yaca_key_destroy(key_rsa_pub);
+       yaca_key_destroy(key_rsa_prv2);
+       yaca_key_destroy(key_rsa_pub2);
+       yaca_key_destroy(key_dsa_prv);
+       yaca_key_destroy(key_dsa_pub);
+       yaca_key_destroy(key_sym);
+       yaca_key_destroy(key_sym2);
+       yaca_key_destroy(iv);
+       yaca_free(encrypted);
+}
+
+BOOST_FIXTURE_TEST_CASE(T703__positive__seal_open_rc2, InitDebugFixture)
+{
+       struct seal_args {
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+               size_t effective_key_bits;
+               size_t split;
+       };
+
+       const std::vector<seal_args> sargs = {
+               {YACA_BCM_CBC, 128, IGNORE, 11},
+               {YACA_BCM_CBC, 192,     64, 22},
+               {YACA_BCM_CBC, 200,    128,  3},
+               {YACA_BCM_CBC, 192,    255,  7},
+               {YACA_BCM_CBC, 192,    713,  2},
+               {YACA_BCM_CBC, 224,      1, 19},
+               {YACA_BCM_CBC, 256,   1024, 19},
+               {YACA_BCM_CFB, 192, IGNORE, 13},
+               {YACA_BCM_CFB, 192,    333, 33},
+               {YACA_BCM_ECB, 272, IGNORE,  8},
+               {YACA_BCM_ECB, 192,    666, 15},
+               {YACA_BCM_OFB, 520, IGNORE, 25},
+               {YACA_BCM_OFB, 224,    999, 35},
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+               yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+               /* SEAL */
+               {
+                       ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_UNSAFE_RC2, sa.bcm,
+                                                                          sa.key_bit_len, &key_sym, &iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.effective_key_bits != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                                               &sa.effective_key_bits, sizeof(size_t));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, sa.split, encrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, sa.split,
+                                                        yaca_seal_update);
+
+                       ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* OPEN */
+               {
+                       ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_UNSAFE_RC2, sa.bcm,
+                                                                          sa.key_bit_len, key_sym, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.effective_key_bits != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                                               &sa.effective_key_bits, sizeof(size_t));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       size_t total = allocate_output(ctx, encrypted_len, sa.split, decrypted);
+                       size_t written;
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, sa.split,
+                                                        yaca_open_update);
+
+                       ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key_prv);
+               yaca_key_destroy(key_pub);
+               yaca_key_destroy(key_sym);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T704__negative__encrypt_decrypt_rc2, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+       /* SEAL */
+       {
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CFB1,
+                                                                  YACA_KEY_LENGTH_192BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CTR,
+                                                                  YACA_KEY_LENGTH_192BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CBC,
+                                                                  YACA_KEY_LENGTH_192BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* OPEN */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CFB1,
+                                                                  YACA_KEY_LENGTH_192BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_UNSAFE_RC2, YACA_BCM_CTR,
+                                                                  YACA_KEY_LENGTH_192BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+       }
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_sym);
+       yaca_key_destroy(iv);
+}
+
+BOOST_FIXTURE_TEST_CASE(T705__positive__open_seal_ccm, InitDebugFixture)
+{
+       struct seal_args {
+               size_t key_bit_len;
+               size_t ccm_tag_len;
+               size_t aad_len;
+       };
+
+       const std::vector<seal_args> sargs = {
+               {128, IGNORE, IGNORE},
+               {128,      4, IGNORE},
+               {128, IGNORE,     13},
+               {128,      6,     23},
+
+               {192, IGNORE, IGNORE},
+               {192,     10, IGNORE},
+               {192, IGNORE,     21},
+               {192,      8,     17},
+
+               {256, IGNORE, IGNORE},
+               {256,     16, IGNORE},
+               {256, IGNORE,     55},
+               {256,     12,     33},
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+               yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *tag = NULL, *aad = NULL;
+               size_t tag_len;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+               /* SEAL */
+               {
+                       ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                          sa.key_bit_len, &key_sym, &iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+                       size_t written;
+
+                       if (sa.ccm_tag_len != IGNORE) {
+                               tag_len = sa.ccm_tag_len;
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG_LEN,
+                                                                                               &tag_len, sizeof(tag_len));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       if (sa.aad_len != IGNORE) {
+                               ret = yaca_malloc(sa.aad_len, (void**)&aad);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_randomize_bytes(aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE,
+                                                                          NULL, &written);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD,
+                                                                                               aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len = written;
+
+                       ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* OPEN */
+               {
+                       ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                          sa.key_bit_len, key_sym, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, encrypted_len, 1, decrypted);
+
+                       ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t written;
+
+                       if (sa.aad_len != IGNORE) {
+                               ret = yaca_open_update(ctx, NULL, encrypted_len,
+                                                                          NULL, &written);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD,
+                                                                                               aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len = written;
+
+                       ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key_prv);
+               yaca_key_destroy(key_pub);
+               yaca_key_destroy(key_sym);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+               yaca_free(tag);
+               yaca_free(aad);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T706__negative__open_seal_ccm, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+       char *tag = NULL, *aad = NULL;
+       size_t tag_len = 0, tag_len_invalid = 17, aad_len = 55;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len, decrypted_len;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+       ret = yaca_malloc(aad_len, (void**)&aad);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(aad, aad_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* SEAL, AAD without pre-update */
+       {
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_key_destroy(key_sym);
+               key_sym = YACA_KEY_NULL;
+               yaca_key_destroy(iv);
+               iv = YACA_KEY_NULL;
+       }
+
+       /* SEAL, pre-update without AAD */
+       {
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG_LEN,
+                                                                               &tag_len_invalid, sizeof(tag_len_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_key_destroy(key_sym);
+               key_sym = YACA_KEY_NULL;
+               yaca_key_destroy(iv);
+               iv = YACA_KEY_NULL;
+       }
+
+       /* SEAL */
+       {
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG_LEN,
+                                                                               &tag_len_invalid, sizeof(tag_len_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_CCM_TAG, (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* OPEN, no TAG */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, AAD without pre-update */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* OPEN, pre-update without AAD */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, no AAD */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, broken TAG */
+       {
+               char *tag2 = NULL;
+               ret = yaca_malloc(tag_len, (void**)&tag2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)tag2, (void*)tag, tag_len);
+               tag2[0] = ~tag2[0];
+               tag2[1] = ~tag2[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag2, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(tag2);
+       }
+
+       /* OPEN, broken AAD */
+       {
+               char *aad2 = NULL;
+               ret = yaca_malloc(aad_len, (void**)&aad2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)aad2, (void*)aad, aad_len);
+               aad2[0] = ~aad2[0];
+               aad2[1] = ~aad2[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad2, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(aad2);
+       }
+
+       /* OPEN, broken ciphertext */
+       {
+               encrypted[0] = ~encrypted[0];
+               encrypted[1] = ~encrypted[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_CCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_CCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_sym);
+       yaca_key_destroy(iv);
+       yaca_free(encrypted);
+       yaca_free(tag);
+       yaca_free(aad);
+}
+
+BOOST_FIXTURE_TEST_CASE(T707__positive__seal_open_gcm, InitDebugFixture)
+{
+       struct seal_args {
+               size_t key_bit_len;
+               size_t gcm_tag_len;
+               size_t aad_len;
+               size_t split;
+       };
+
+       const std::vector<seal_args> sargs = {
+               {128, IGNORE, IGNORE, 11},
+               {128,      4, IGNORE, 12},
+               {128, IGNORE,     21, 13},
+               {128,     13,     22, 14},
+
+               {192, IGNORE, IGNORE, 22},
+               {192,      8, IGNORE, 23},
+               {192, IGNORE,     32, 24},
+               {192,     15,     33, 25},
+
+               {256, IGNORE, IGNORE, 33},
+               {256,     14, IGNORE, 34},
+               {256, IGNORE,     17, 35},
+               {256,     16,     44, 36},
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+               yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len = 0, decrypted_len = 0;
+
+               char *tag = NULL, *aad = NULL;
+               size_t tag_len;
+
+               generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+               /* SEAL */
+               {
+                       ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                          sa.key_bit_len, &key_sym, &iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, INPUT_DATA_SIZE, sa.split, encrypted);
+                       size_t written;
+
+                       if (sa.aad_len != IGNORE) {
+                               ret = yaca_malloc(sa.aad_len, (void**)&aad);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_randomize_bytes(aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD,
+                                                                                               aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        encrypted, encrypted_len, sa.split,
+                                                        yaca_seal_update);
+
+                       ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       encrypted_len += written;
+
+                       BOOST_REQUIRE(encrypted_len <= total);
+                       ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.gcm_tag_len != IGNORE) {
+                               tag_len = sa.gcm_tag_len;
+
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG_LEN,
+                                                                                               &tag_len, sizeof(tag_len));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       }
+
+                       ret = yaca_context_get_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                                       (void**)&tag, &tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* OPEN */
+               {
+                       ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                          sa.key_bit_len, key_sym, iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       size_t total = allocate_output(ctx, encrypted_len, sa.split, decrypted);
+                       size_t written;
+
+                       if (sa.aad_len != IGNORE) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD,
+                                                                                               aad, sa.aad_len);
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, encrypted, encrypted_len,
+                                                        decrypted, decrypted_len, sa.split,
+                                                        yaca_open_update);
+
+                       ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                                       tag, tag_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       decrypted_len += written;
+
+                       BOOST_REQUIRE(decrypted_len <= total);
+                       ret = yaca_realloc(decrypted_len, (void **)&decrypted);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key_prv);
+               yaca_key_destroy(key_pub);
+               yaca_key_destroy(key_sym);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+               yaca_free(tag);
+               yaca_free(aad);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T708__negative__seal_open_gcm, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len = 0, decrypted_len = 0;
+
+       char *tag = NULL, *aad = NULL;
+       size_t tag_len = 0, tag_len_invalid = 17, aad_len = 55;
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_prv, &key_pub);
+
+       ret = yaca_malloc(aad_len, (void**)&aad);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_randomize_bytes(aad, aad_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       /* SEAL */
+       {
+               ret = yaca_seal_initialize(&ctx, key_pub, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, &key_sym, &iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               size_t total = allocate_output(ctx, INPUT_DATA_SIZE, 1, encrypted);
+               size_t written;
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_update(ctx, NULL, INPUT_DATA_SIZE, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len = written;
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               encrypted_len += written;
+               BOOST_REQUIRE(encrypted_len <= total);
+               ret = yaca_realloc(encrypted_len, (void **)&encrypted);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_seal_update(ctx, INPUT_DATA, INPUT_DATA_SIZE, encrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_seal_finalize(ctx, encrypted + encrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG_LEN,
+                                                                               &tag_len_invalid, sizeof(tag_len_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_property(ctx, YACA_PROPERTY_GCM_TAG,
+                                                                               (void**)&tag, &tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* OPEN, no TAG */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, no AAD */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN */
+       {
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, NULL, encrypted_len, NULL, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       /* OPEN, broken TAG */
+       {
+               char *tag2 = NULL;
+               ret = yaca_malloc(tag_len, (void**)&tag2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)tag2, (void*)tag, tag_len);
+               tag2[0] = ~tag2[0];
+               tag2[1] = ~tag2[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag2, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(tag2);
+       }
+
+       /* OPEN, broken AAD */
+       {
+               char *aad2 = NULL;
+               ret = yaca_malloc(aad_len, (void**)&aad2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               memcpy((void*)aad2, (void*)aad, aad_len);
+               aad2[0] = ~aad2[0];
+               aad2[1] = ~aad2[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad2, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+               yaca_free(aad2);
+       }
+
+       /* OPEN, broken ciphertext */
+       {
+               encrypted[0] = ~encrypted[0];
+               encrypted[1] = ~encrypted[1];
+
+               ret = yaca_open_initialize(&ctx, key_prv, YACA_ENCRYPT_AES, YACA_BCM_GCM,
+                                                                  YACA_KEY_LENGTH_256BIT, key_sym, iv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               allocate_output(ctx, encrypted_len, 1, decrypted);
+               size_t written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_AAD, aad, aad_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_update(ctx, encrypted, encrypted_len, decrypted, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               decrypted_len = written;
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_GCM_TAG, tag, tag_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_open_finalize(ctx, decrypted + decrypted_len, &written);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(decrypted);
+               decrypted = NULL;
+       }
+
+       yaca_key_destroy(key_prv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_sym);
+       yaca_key_destroy(iv);
+       yaca_free(encrypted);
+       yaca_free(tag);
+       yaca_free(aad);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_sign.cpp b/tests/test_sign.cpp
new file mode 100644 (file)
index 0000000..9aed73d
--- /dev/null
@@ -0,0 +1,950 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_sign.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Signature API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_sign.h>
+#include <yaca_key.h>
+#include <yaca_digest.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+namespace {
+
+using update_fun_3_t = int(yaca_context_h ctx, const char *input, size_t input_len);
+
+void call_update_loop(yaca_context_h &ctx, const char *input, size_t input_len,
+                                         size_t split, update_fun_3_t *fun)
+{
+       BOOST_REQUIRE_MESSAGE(split >= 1, "Fix your test");
+
+       int ret;
+       size_t left = input_len;
+       size_t part = input_len / split;
+
+       BOOST_REQUIRE_MESSAGE(part >= 1, "Fix your test");
+
+       for (;;) {
+               ret = fun(ctx, input, part);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               input += part;
+               left -= part;
+
+               if (left == 0)
+                       break;
+
+               if (left < part)
+                       part = left;
+       }
+}
+
+} //namespace
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_SIGN)
+
+BOOST_FIXTURE_TEST_CASE(T801__positive__sign_verify, InitDebugFixture)
+{
+       struct sign_args {
+               yaca_key_type_e type_prv;
+               yaca_key_bit_length_e key_bit_len;
+               yaca_digest_algorithm_e digest;
+               yaca_padding_e pad;
+               size_t split;
+       };
+
+       const std::vector<sign_args> sargs = {
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT,
+                YACA_DIGEST_MD5, YACA_INVALID_PADDING, 27},
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT,
+                YACA_DIGEST_MD5, YACA_PADDING_PKCS1_PSS, 14},
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_2048BIT,
+                YACA_DIGEST_SHA1, YACA_PADDING_X931, 34},
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT,
+                YACA_DIGEST_SHA384, YACA_PADDING_PKCS1, 9},
+               {YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_2048BIT,
+                YACA_DIGEST_SHA512, YACA_PADDING_PKCS1_PSS, 12},
+
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT,
+                YACA_DIGEST_SHA256, YACA_INVALID_PADDING, 5},
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT,
+                YACA_DIGEST_SHA224, YACA_INVALID_PADDING, 31},
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_2048BIT,
+                YACA_DIGEST_SHA1, YACA_INVALID_PADDING, 29},
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT,
+                YACA_DIGEST_SHA384, YACA_INVALID_PADDING, 19},
+               {YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_2048BIT,
+                YACA_DIGEST_SHA512, YACA_INVALID_PADDING, 11},
+
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP256K1,
+                YACA_DIGEST_SHA256, YACA_INVALID_PADDING, 13},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP384R1,
+                YACA_DIGEST_SHA224, YACA_INVALID_PADDING, 23},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_SECP521R1,
+                YACA_DIGEST_SHA1, YACA_INVALID_PADDING, 33},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME192V1,
+                YACA_DIGEST_SHA384, YACA_INVALID_PADDING, 22},
+               {YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)YACA_KEY_LENGTH_EC_PRIME256V1,
+                YACA_DIGEST_SHA512, YACA_INVALID_PADDING, 20},
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key_prv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+
+               char *signature = NULL;
+               size_t signature_len;
+
+               generate_asymmetric_keys(sa.type_prv, sa.key_bit_len, &key_prv, &key_pub);
+
+               /* SIGN */
+               {
+                       ret = yaca_sign_initialize(&ctx, sa.digest, key_prv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.pad != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                                               &sa.pad, sizeof(sa.pad));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        sa.split, &yaca_sign_update);
+
+                       ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_malloc(signature_len, (void **)&signature);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_sign_finalize(ctx, signature, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* VERIFY */
+               {
+                       ret = yaca_verify_initialize(&ctx, sa.digest, key_pub);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       if (sa.pad != YACA_INVALID_PADDING) {
+                               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                                               &sa.pad, sizeof(sa.pad));
+                               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+                       }
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        sa.split + 3, &yaca_verify_update);
+
+                       ret = yaca_verify_finalize(ctx, signature, signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               yaca_key_destroy(key_prv);
+               yaca_key_destroy(key_pub);
+               yaca_free(signature);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T802__negative__sign_verify, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL, ctx_digest = YACA_CONTEXT_NULL;
+       yaca_key_h key_rsa_prv = YACA_KEY_NULL, key_rsa_pub = YACA_KEY_NULL;
+       yaca_key_h key_rsa_prv2 = YACA_KEY_NULL, key_rsa_pub2 = YACA_KEY_NULL;
+       yaca_key_h key_dsa_prv = YACA_KEY_NULL, key_dsa_pub = YACA_KEY_NULL;
+       yaca_key_h key_sym = YACA_KEY_NULL, key_rsa_prv_short = YACA_KEY_NULL;
+       yaca_padding_e pad_invalid = YACA_PADDING_X931, pad_none = YACA_PADDING_NONE;
+       yaca_padding_e pad = YACA_PADDING_PKCS1, pad2 = YACA_PADDING_PKCS1_PSS;
+
+       size_t len = 128;
+
+       char *signature = NULL;
+       size_t signature_len;
+
+       ret = yaca_digest_initialize(&ctx_digest, YACA_DIGEST_MD5);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key_sym);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_rsa_prv_short);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_rsa_prv, &key_rsa_pub);
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_rsa_prv2, &key_rsa_pub2);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_1024BIT, &key_dsa_prv, &key_dsa_pub);
+
+       /* SIGN */
+       {
+               ret = yaca_sign_initialize(NULL, YACA_DIGEST_MD5, key_rsa_prv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_INVALID_DIGEST_ALGORITHM, key_rsa_prv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_MD5, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_MD5, key_sym);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_SHA384, key_rsa_prv_short);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_prv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               NULL, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_none, sizeof(pad_none));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(pad_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(YACA_CONTEXT_NULL, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_update(ctx, NULL, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, 0);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_update(ctx_digest, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_output_length(ctx, 1, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature_len, (void **)&signature);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(YACA_CONTEXT_NULL, signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_finalize(ctx, NULL, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_finalize(ctx, signature, NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_finalize(ctx, signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_finalize(ctx, signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY */
+       {
+               ret = yaca_verify_initialize(NULL, YACA_DIGEST_MD5, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_INVALID_DIGEST_ALGORITHM, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_prv);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, key_sym);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_SHA384, key_rsa_prv_short);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_INVALID_PROPERTY,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               NULL, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_RC2_EFFECTIVE_KEY_BITS,
+                                                                               &len, sizeof(size_t));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_none, sizeof(pad_none));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(pad_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_update(YACA_CONTEXT_NULL, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_update(ctx, NULL, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, 0);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_update(ctx_digest, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_finalize(YACA_CONTEXT_NULL, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_finalize(ctx, NULL, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_finalize(ctx, signature, 0);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_finalize(ctx_digest, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len - 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               ret = yaca_verify_finalize(ctx, signature + 1, signature_len - 1);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY, wrong algo */
+       {
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_SHA1, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY, wrong key */
+       {
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_pub2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY, wrong padding */
+       {
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_MD5, key_rsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad2, sizeof(pad2));
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_verify_finalize(ctx, signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* SIGN DSA */
+       {
+               ret = yaca_sign_initialize(&ctx, YACA_DIGEST_SHA1, key_dsa_prv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad2, sizeof(pad2));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(pad_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_none, sizeof(pad_none));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY DSA */
+       {
+               ret = yaca_verify_initialize(&ctx, YACA_DIGEST_SHA1, key_dsa_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad, sizeof(pad));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad2, sizeof(pad2));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_invalid, sizeof(pad_invalid));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_context_set_property(ctx, YACA_PROPERTY_PADDING,
+                                                                               &pad_none, sizeof(pad_none));
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       yaca_key_destroy(key_rsa_prv);
+       yaca_key_destroy(key_rsa_pub);
+       yaca_key_destroy(key_rsa_prv2);
+       yaca_key_destroy(key_rsa_pub2);
+       yaca_key_destroy(key_rsa_prv_short);
+       yaca_key_destroy(key_dsa_prv);
+       yaca_key_destroy(key_dsa_pub);
+       yaca_key_destroy(key_sym);
+       yaca_context_destroy(ctx_digest);
+       yaca_free(signature);
+}
+
+BOOST_FIXTURE_TEST_CASE(T803__positive__sign_cmac, InitDebugFixture)
+{
+       struct cmac_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_encrypt_algorithm_e algo;
+               size_t split;
+       };
+
+       const std::vector<cmac_args> cargs = {
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT,
+                YACA_ENCRYPT_AES, 11},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_ENCRYPT_CAST5, 22},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT,
+                YACA_ENCRYPT_3DES_3TDEA, 33},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT,
+                YACA_ENCRYPT_UNSAFE_RC2, 44},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_64BIT,
+                YACA_ENCRYPT_UNSAFE_DES, 13},
+
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_ENCRYPT_AES, 15},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_ENCRYPT_CAST5, 41},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT,
+                YACA_ENCRYPT_3DES_3TDEA, 17},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_ENCRYPT_UNSAFE_RC2, 9},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_64BIT,
+                YACA_ENCRYPT_UNSAFE_DES, 12},
+       };
+
+       for (const auto &ca: cargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL;
+
+               char *signature = NULL, *signature2 = NULL;
+               size_t signature_len, signature2_len;
+
+               ret = yaca_key_generate(ca.type, ca.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               /* SIGN */
+               {
+                       ret = yaca_sign_initialize_cmac(&ctx, ca.algo, key);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        ca.split, yaca_sign_update);
+
+                       ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_malloc(signature_len, (void **)&signature);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_sign_finalize(ctx, signature, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* VERIFY */
+               {
+                       ret = yaca_sign_initialize_cmac(&ctx, ca.algo, key);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        ca.split + 3, yaca_sign_update);
+
+                       ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_malloc(signature2_len, (void **)&signature2);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+
+                       BOOST_REQUIRE(signature_len == signature2_len);
+                       ret = yaca_memcmp(signature, signature2, signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               }
+
+               yaca_key_destroy(key);
+               yaca_free(signature);
+               yaca_free(signature2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T804__negative__sign_cmac, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, key2 = YACA_KEY_NULL;
+       yaca_key_h key_rsa = YACA_KEY_NULL, key_dsa = YACA_KEY_NULL;
+
+       char *signature = NULL, *signature2 = NULL;
+       size_t signature_len, signature2_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &key2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_rsa);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_dsa);
+
+       /* SIGN */
+       {
+               ret = yaca_sign_initialize_cmac(NULL, YACA_ENCRYPT_AES, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_INVALID_ENCRYPT_ALGORITHM, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_AES, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_AES, key_rsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_AES, key_dsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_AES, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature_len, (void **)&signature);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY, wrong algo */
+       {
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_3DES_3TDEA, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature2_len, (void **)&signature2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               signature2_len = std::min(signature_len, signature2_len);
+               ret = yaca_memcmp(signature, signature2, signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(signature2);
+               signature2 = NULL;
+       }
+
+       /* VERIFY, wrong key */
+       {
+               ret = yaca_sign_initialize_cmac(&ctx, YACA_ENCRYPT_AES, key2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature2_len, (void **)&signature2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(signature_len == signature2_len);
+               ret = yaca_memcmp(signature, signature2, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(signature2);
+               signature2 = NULL;
+       }
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key2);
+       yaca_key_destroy(key_rsa);
+       yaca_key_destroy(key_dsa);
+       yaca_free(signature);
+}
+
+BOOST_FIXTURE_TEST_CASE(T805__positive__sign_hmac, InitDebugFixture)
+{
+       struct hmac_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_digest_algorithm_e digest;
+               size_t split;
+       };
+
+       const std::vector<hmac_args> hargs = {
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT,
+                YACA_DIGEST_MD5, 13},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_DIGEST_SHA1, 32},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT,
+                YACA_DIGEST_SHA224, 23},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT,
+                YACA_DIGEST_SHA256, 20},
+               {YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_UNSAFE_64BIT,
+                YACA_DIGEST_SHA384, 13},
+
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_DIGEST_MD5, 9},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_DIGEST_SHA1, 7},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_192BIT,
+                YACA_DIGEST_SHA224, 14},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_128BIT,
+                YACA_DIGEST_SHA384, 20},
+               {YACA_KEY_TYPE_DES, YACA_KEY_LENGTH_UNSAFE_64BIT,
+                YACA_DIGEST_SHA512, 10},
+       };
+
+       for (const auto &ha: hargs) {
+               int ret;
+               yaca_context_h ctx = YACA_CONTEXT_NULL;
+               yaca_key_h key = YACA_KEY_NULL;
+
+               char *signature = NULL, *signature2 = NULL;
+               size_t signature_len, signature2_len;
+
+               ret = yaca_key_generate(ha.type, ha.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               /* SIGN */
+               {
+                       ret = yaca_sign_initialize_hmac(&ctx, ha.digest, key);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        ha.split, yaca_sign_update);
+
+                       ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_malloc(signature_len, (void **)&signature);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_sign_finalize(ctx, signature, &signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+               }
+
+               /* VERIFY */
+               {
+                       ret = yaca_sign_initialize_hmac(&ctx, ha.digest, key);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       call_update_loop(ctx, INPUT_DATA, INPUT_DATA_SIZE,
+                                                        ha.split + 3, yaca_sign_update);
+
+                       ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_malloc(signature2_len, (void **)&signature2);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+                       yaca_context_destroy(ctx);
+                       ctx = YACA_CONTEXT_NULL;
+
+                       BOOST_REQUIRE(signature_len == signature2_len);
+                       ret = yaca_memcmp(signature, signature2, signature_len);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               }
+
+               yaca_key_destroy(key);
+               yaca_free(signature);
+               yaca_free(signature2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T806__negative__sign_hmac, InitDebugFixture)
+{
+       int ret;
+       yaca_context_h ctx = YACA_CONTEXT_NULL;
+       yaca_key_h key = YACA_KEY_NULL, key2 = YACA_KEY_NULL;
+       yaca_key_h key_rsa = YACA_KEY_NULL, key_dsa = YACA_KEY_NULL;
+
+       char *signature = NULL, *signature2 = NULL;
+       size_t signature_len, signature2_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &key2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       generate_asymmetric_keys(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_rsa);
+       generate_asymmetric_keys(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_dsa);
+
+       /* SIGN */
+       {
+               ret = yaca_sign_initialize_hmac(NULL, YACA_DIGEST_MD5, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_INVALID_DIGEST_ALGORITHM, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_MD5, YACA_KEY_NULL);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_MD5, key_rsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_MD5, key_dsa);
+               BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_MD5, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature_len, (void **)&signature);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+       }
+
+       /* VERIFY, wrong algo */
+       {
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_SHA1, key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature2_len, (void **)&signature2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               signature2_len = std::min(signature_len, signature2_len);
+               ret = yaca_memcmp(signature, signature2, signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(signature2);
+               signature2 = NULL;
+       }
+
+       /* VERIFY, wrong key */
+       {
+               ret = yaca_sign_initialize_hmac(&ctx, YACA_DIGEST_MD5, key2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_update(ctx, INPUT_DATA, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_context_get_output_length(ctx, 0, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_malloc(signature2_len, (void **)&signature2);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_sign_finalize(ctx, signature2, &signature2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(signature_len == signature2_len);
+               ret = yaca_memcmp(signature, signature2, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+               yaca_context_destroy(ctx);
+               ctx = YACA_CONTEXT_NULL;
+               yaca_free(signature2);
+               signature2 = NULL;
+       }
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key2);
+       yaca_key_destroy(key_rsa);
+       yaca_key_destroy(key_dsa);
+       yaca_free(signature);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/test_simple.cpp b/tests/test_simple.cpp
new file mode 100644 (file)
index 0000000..59f25eb
--- /dev/null
@@ -0,0 +1,755 @@
+/*
+ *  Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file    test_simple.cpp
+ * @author  Lukasz Pawelczyk <l.pawelczyk@samsung.com>
+ * @brief   Simple API unit tests.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+#include <yaca_crypto.h>
+#include <yaca_encrypt.h>
+#include <yaca_key.h>
+#include <yaca_simple.h>
+#include <yaca_error.h>
+
+#include "common.h"
+
+
+BOOST_AUTO_TEST_SUITE(TESTS_SIMPLE)
+
+BOOST_FIXTURE_TEST_CASE(T301__positive__simple_encrypt_decrypt, InitDebugFixture)
+{
+       struct encrypt_args {
+               yaca_encrypt_algorithm_e algo;
+               yaca_block_cipher_mode_e bcm;
+               size_t key_bit_len;
+       };
+
+       const std::vector<struct encrypt_args> eargs = {
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_AES,
+                yaca_block_cipher_mode_e::YACA_BCM_CBC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_AES,
+                yaca_block_cipher_mode_e::YACA_BCM_CFB,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_AES,
+                yaca_block_cipher_mode_e::YACA_BCM_ECB,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_IV_128BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_UNSAFE_DES,
+                yaca_block_cipher_mode_e::YACA_BCM_CBC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_UNSAFE_64BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_3DES_3TDEA,
+                yaca_block_cipher_mode_e::YACA_BCM_ECB,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_192BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_UNSAFE_RC4,
+                yaca_block_cipher_mode_e::YACA_BCM_NONE,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_192BIT},
+               {yaca_encrypt_algorithm_e::YACA_ENCRYPT_CAST5,
+                yaca_block_cipher_mode_e::YACA_BCM_OFB,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_UNSAFE_128BIT}
+       };
+
+       for (const auto &ea: eargs) {
+               int ret;
+               yaca_key_h sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+               size_t iv_bit_len;
+               char *encrypted = NULL, *decrypted = NULL;
+               size_t encrypted_len, decrypted_len;
+
+               ret = yaca_encrypt_get_iv_bit_length(ea.algo, ea.bcm, ea.key_bit_len, &iv_bit_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, ea.key_bit_len, &sym);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               if (iv_bit_len > 0) {
+                       ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len, &iv);
+                       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               }
+
+               ret = yaca_simple_encrypt(ea.algo, ea.bcm, sym, iv, INPUT_DATA, INPUT_DATA_SIZE,
+                                                                 &encrypted, &encrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_decrypt(ea.algo, ea.bcm, sym, iv, encrypted, encrypted_len,
+                                                                 &decrypted, &decrypted_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(decrypted_len == INPUT_DATA_SIZE);
+               ret = yaca_memcmp(INPUT_DATA, decrypted, INPUT_DATA_SIZE);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(sym);
+               yaca_key_destroy(iv);
+               yaca_free(encrypted);
+               yaca_free(decrypted);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T302__negative__simple_encrypt_decrypt, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h sym = YACA_KEY_NULL, iv = YACA_KEY_NULL;
+       yaca_key_h sym2 = YACA_KEY_NULL, iv2 = YACA_KEY_NULL;
+       size_t iv_bit_len;
+       char *encrypted = NULL, *decrypted = NULL;
+       size_t encrypted_len, decrypted_len;
+
+       ret = yaca_encrypt_get_iv_bit_length(YACA_ENCRYPT_AES, YACA_BCM_CBC,
+                                                                                YACA_KEY_LENGTH_256BIT, &iv_bit_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &sym);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_192BIT, &sym2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len, &iv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_IV, iv_bit_len * 2, &iv2);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_encrypt(YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC, sym, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE, sym, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, YACA_KEY_NULL, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, YACA_KEY_NULL,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         NULL, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         INPUT_DATA, 0,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         NULL, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_encrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                         &encrypted, &encrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_decrypt(YACA_INVALID_ENCRYPT_ALGORITHM, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_INVALID_BLOCK_CIPHER_MODE, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, NULL, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, NULL,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         NULL, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, 0,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         NULL, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_3DES_3TDEA, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_ECB, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym2, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv2,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len - 1,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted + 1, encrypted_len - 1,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       encrypted[encrypted_len - 1] = ~encrypted[encrypted_len - 1];
+       encrypted[encrypted_len - 2] = ~encrypted[encrypted_len - 2];
+       ret = yaca_simple_decrypt(YACA_ENCRYPT_AES, YACA_BCM_CBC, sym, iv,
+                                                         encrypted, encrypted_len,
+                                                         &decrypted, &decrypted_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(sym);
+       yaca_key_destroy(sym2);
+       yaca_key_destroy(iv);
+       yaca_key_destroy(iv2);
+       yaca_free(encrypted);
+       yaca_free(decrypted);
+}
+
+BOOST_FIXTURE_TEST_CASE(T303__positive__simple_calculate_digest, InitDebugFixture)
+{
+       struct digest_args {
+               yaca_digest_algorithm_e algo = YACA_DIGEST_SHA256;
+               size_t expected;
+       };
+
+       const std::vector<struct digest_args> dargs = {
+               {yaca_digest_algorithm_e::YACA_DIGEST_MD5, 16},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA1, 20},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA224, 28},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA256, 32},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA384, 48},
+               {yaca_digest_algorithm_e::YACA_DIGEST_SHA512, 64}
+       };
+
+       for (const auto &da: dargs) {
+               int ret;
+               char *digest = NULL;
+               size_t digest_len;
+
+               ret = yaca_simple_calculate_digest(da.algo, INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                  &digest, &digest_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(digest_len == da.expected);
+
+               yaca_free(digest);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T304__negative__simple_calculate_digest, InitDebugFixture)
+{
+       int ret;
+       char *digest = NULL;
+       size_t digest_len;
+
+       ret = yaca_simple_calculate_digest(YACA_INVALID_DIGEST_ALGORITHM, INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          &digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_digest(YACA_DIGEST_SHA256, NULL, INPUT_DATA_SIZE,
+                                                                          &digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_digest(YACA_DIGEST_SHA256, INPUT_DATA, 0,
+                                                                          &digest, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_digest(YACA_DIGEST_SHA256, INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          NULL, &digest_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_digest(YACA_DIGEST_SHA256, INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          &digest, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+}
+
+BOOST_FIXTURE_TEST_CASE(T305__positive__simple_calculate_verify_signature, InitDebugFixture)
+{
+       struct signature_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_digest_algorithm_e algo;
+       };
+
+       const std::vector<struct signature_args> sargs = {
+               {yaca_key_type_e::YACA_KEY_TYPE_RSA_PRIV,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_1024BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_MD5},
+               {yaca_key_type_e::YACA_KEY_TYPE_RSA_PRIV,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_2048BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_MD5},
+               {yaca_key_type_e::YACA_KEY_TYPE_RSA_PRIV,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_1024BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA256},
+               {yaca_key_type_e::YACA_KEY_TYPE_DSA_PRIV,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_1024BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA256},
+               {yaca_key_type_e::YACA_KEY_TYPE_DSA_PRIV,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_1024BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA512},
+               {yaca_key_type_e::YACA_KEY_TYPE_EC_PRIV,
+                (yaca_key_bit_length_e)yaca_key_bit_length_ec_e::YACA_KEY_LENGTH_EC_SECP256K1,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA256}
+       };
+
+       for (const auto &sa: sargs) {
+               int ret;
+               yaca_key_h key_priv = YACA_KEY_NULL;
+               yaca_key_h key_pub = YACA_KEY_NULL;
+
+               char *signature = NULL;
+               size_t signature_len;
+
+               ret = yaca_key_generate(sa.type, sa.len, &key_priv);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_key_extract_public(key_priv, &key_pub);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_calculate_signature(sa.algo, key_priv,
+                                                                                         INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                         &signature, &signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+               BOOST_REQUIRE(signature_len > 0);
+
+               ret = yaca_simple_verify_signature(sa.algo, key_pub,
+                                                                                  INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                  signature, signature_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key_priv);
+               yaca_key_destroy(key_pub);
+               yaca_free(signature);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T306__negative__simple_calculate_verify_signature, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key_priv = YACA_KEY_NULL, key_pub = YACA_KEY_NULL;
+       yaca_key_h key_ec = YACA_KEY_NULL, key_dsa = YACA_KEY_NULL;
+
+       char *signature = NULL;
+       size_t signature_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_priv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_extract_public(key_priv, &key_pub);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_DSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_dsa);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_EC_PRIV, YACA_KEY_LENGTH_EC_PRIME256V1, &key_ec);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_calculate_signature(YACA_INVALID_DIGEST_ALGORITHM, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_SHA384, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_SHA512, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, YACA_KEY_NULL,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_priv,
+                                                                                 NULL, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_priv,
+                                                                                 INPUT_DATA, 0,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 NULL, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_dsa,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_ec,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_pub,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_signature(YACA_DIGEST_MD5, key_priv,
+                                                                                 INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                 &signature, &signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_verify_signature(YACA_INVALID_DIGEST_ALGORITHM, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_SHA384, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_SHA512, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, YACA_KEY_NULL,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_priv,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_ec,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          NULL, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, 0,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          NULL, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_SHA1, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE - 1,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA + 1, INPUT_DATA_SIZE - 1,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len - 1);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature + 1, signature_len - 1);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       signature[0] = ~signature[0];
+       signature[1] = ~signature[1];
+       ret = yaca_simple_verify_signature(YACA_DIGEST_MD5, key_pub,
+                                                                          INPUT_DATA, INPUT_DATA_SIZE,
+                                                                          signature, signature_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_DATA_MISMATCH);
+
+       yaca_key_destroy(key_priv);
+       yaca_key_destroy(key_pub);
+       yaca_key_destroy(key_dsa);
+       yaca_key_destroy(key_ec);
+       yaca_free(signature);
+}
+
+BOOST_FIXTURE_TEST_CASE(T307__positive__simple_calculate_hmac, InitDebugFixture)
+{
+       struct hmac_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_digest_algorithm_e algo;
+       };
+
+       const std::vector<struct hmac_args> hargs = {
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_MD5},
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA256},
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA512},
+               {yaca_key_type_e::YACA_KEY_TYPE_DES,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_UNSAFE_128BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA1},
+               {yaca_key_type_e::YACA_KEY_TYPE_DES,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_192BIT,
+                yaca_digest_algorithm_e::YACA_DIGEST_SHA384}
+       };
+
+       for (const auto &ha: hargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+               char *mac1 = NULL, *mac2 = NULL;
+               size_t mac1_len, mac2_len;
+
+               ret = yaca_key_generate(ha.type, ha.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_calculate_hmac(ha.algo, key,
+                                                                                INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                &mac1, &mac1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_calculate_hmac(ha.algo, key,
+                                                                                INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                &mac2, &mac2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(mac1_len == mac2_len);
+               ret = yaca_memcmp(mac1, mac2, mac1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_free(mac1);
+               yaca_free(mac2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T308__negative__simple_calculate_hmac, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key = YACA_KEY_NULL, key_prv = YACA_KEY_NULL;
+       char *mac = NULL;
+       size_t mac_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_prv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_calculate_hmac(YACA_INVALID_DIGEST_ALGORITHM, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, YACA_KEY_NULL,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, key_prv,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, key,
+                                                                        NULL, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, key,
+                                                                        INPUT_DATA, 0,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        NULL, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_hmac(YACA_DIGEST_MD5, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, NULL);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key_prv);
+}
+
+BOOST_FIXTURE_TEST_CASE(T309__positive__simple_calculate_cmac, InitDebugFixture)
+{
+       struct cmac_args {
+               yaca_key_type_e type;
+               yaca_key_bit_length_e len;
+               yaca_encrypt_algorithm_e algo;
+       };
+
+       const std::vector<struct cmac_args> cargs = {
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT,
+                yaca_encrypt_algorithm_e::YACA_ENCRYPT_AES},
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_256BIT,
+                yaca_encrypt_algorithm_e::YACA_ENCRYPT_AES},
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_192BIT,
+                yaca_encrypt_algorithm_e::YACA_ENCRYPT_3DES_3TDEA},
+               {yaca_key_type_e::YACA_KEY_TYPE_DES,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_UNSAFE_64BIT,
+                yaca_encrypt_algorithm_e::YACA_ENCRYPT_UNSAFE_DES},
+               {yaca_key_type_e::YACA_KEY_TYPE_SYMMETRIC,
+                yaca_key_bit_length_e::YACA_KEY_LENGTH_UNSAFE_128BIT,
+                yaca_encrypt_algorithm_e::YACA_ENCRYPT_CAST5}};
+
+       for (const auto &ha: cargs) {
+               int ret;
+               yaca_key_h key = YACA_KEY_NULL;
+               char *mac1 = NULL, *mac2 = NULL;
+               size_t mac1_len, mac2_len;
+
+               ret = yaca_key_generate(ha.type, ha.len, &key);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_calculate_cmac(ha.algo, key,
+                                                                                INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                &mac1, &mac1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               ret = yaca_simple_calculate_cmac(ha.algo, key,
+                                                                                INPUT_DATA, INPUT_DATA_SIZE,
+                                                                                &mac2, &mac2_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               BOOST_REQUIRE(mac1_len == mac2_len);
+               ret = yaca_memcmp(mac1, mac2, mac1_len);
+               BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+               yaca_key_destroy(key);
+               yaca_free(mac1);
+               yaca_free(mac2);
+       }
+}
+
+BOOST_FIXTURE_TEST_CASE(T3010__negative__simple_calculate_cmac, InitDebugFixture)
+{
+       int ret;
+       yaca_key_h key = YACA_KEY_NULL, key_prv = YACA_KEY_NULL;
+       char *mac = NULL;
+       size_t mac_len;
+
+       ret = yaca_key_generate(YACA_KEY_TYPE_SYMMETRIC, YACA_KEY_LENGTH_256BIT, &key);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+       ret = yaca_key_generate(YACA_KEY_TYPE_RSA_PRIV, YACA_KEY_LENGTH_512BIT, &key_prv);
+       BOOST_REQUIRE(ret == YACA_ERROR_NONE);
+
+       ret = yaca_simple_calculate_cmac(YACA_INVALID_ENCRYPT_ALGORITHM, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, YACA_KEY_NULL,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, key_prv,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, key,
+                                                                        NULL, INPUT_DATA_SIZE,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, key,
+                                                                        INPUT_DATA, 0,
+                                                                        &mac, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        NULL, &mac_len);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       ret = yaca_simple_calculate_cmac(YACA_ENCRYPT_AES, key,
+                                                                        INPUT_DATA, INPUT_DATA_SIZE,
+                                                                        &mac, 0);
+       BOOST_REQUIRE(ret == YACA_ERROR_INVALID_PARAMETER);
+
+       yaca_key_destroy(key);
+       yaca_key_destroy(key_prv);
+}
+
+BOOST_AUTO_TEST_SUITE_END()