CKM: Cipher API tests 34/293334/6
authorKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Wed, 24 May 2023 10:31:42 +0000 (12:31 +0200)
committerKrzysztof Jackiewicz <k.jackiewicz@samsung.com>
Tue, 6 Jun 2023 14:43:08 +0000 (16:43 +0200)
Also reduce big data size to speed up the testing

Change-Id: I8ea762d4aecdfdc6c57f12f5a708185e68830858

packaging/security-tests.spec
src/ckm/ckm-common.cpp
src/ckm/ckm-common.h
src/ckm/unprivileged/encryption-decryption-env.cpp
src/ckm/unprivileged/encryption-decryption-env.h
src/ckm/unprivileged/encryption-decryption.cpp

index cd7b9c0..0b398af 100644 (file)
@@ -12,6 +12,7 @@ BuildRequires: libattr-devel
 BuildRequires: pkgconfig(libcap)
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(security-manager)
+# TODO update when cipher API is released
 BuildRequires: pkgconfig(key-manager) >= 0.1.49
 BuildRequires: key-manager-initial-values
 BuildRequires: util-linux
index 5479eb6..c34aaa2 100644 (file)
@@ -606,6 +606,11 @@ RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer)
     return RawBufferPtr(buffer, ckmc_buffer_free);
 }
 
+CipherCtxPtr create_cipher_ctx(ckmc_cipher_ctx_h ctx)
+{
+    return CipherCtxPtr(ctx, ckmc_cipher_free);
+}
+
 CKM::Policy generate_ckm_policy(int iterator_nr) {
     if (iterator_nr % 2) { // policy with password and with / without extractable flag
         return CKM::Policy(CKM::Password("test_pwd"), iterator_nr % 4);
index c0578ac..f930657 100644 (file)
@@ -196,6 +196,7 @@ public:
 
 typedef std::shared_ptr<ckmc_raw_buffer_s> RawBufferPtr;
 typedef std::shared_ptr<struct __ckmc_param_list> ParamListPtr;
+typedef std::shared_ptr<struct __ckmc_cipher_ctx> CipherCtxPtr;
 
 ParamListPtr createParamListPtr();
 void setParam(ParamListPtr& params, ckmc_param_name_e name, ckmc_raw_buffer_s* buffer);
@@ -205,6 +206,8 @@ void assert_buffers_equal(const ckmc_raw_buffer_s* b1, const ckmc_raw_buffer_s*
 
 RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer);
 
+CipherCtxPtr create_cipher_ctx(ckmc_cipher_ctx_h ctx);
+
 
 template <typename F, typename... Args>
 void test_no_observer(F&& func, Args... args)
index 03dc266..16017d4 100644 (file)
@@ -145,3 +145,187 @@ EncryptionError AsyncApi::ckmError2Result(int error)
     default:                                   return EncryptionError::OTHER;
     }
 }
+
+int CipherApi::crypt(ckmc_cipher_ctx_h ctx,
+                     unsigned char *ptr,
+                     size_t left,
+                     CKM::RawBuffer& output)
+{
+    const size_t CHUNK_SIZE = 80;
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* in = nullptr;
+    size_t size = CHUNK_SIZE;
+    int ret = CKMC_ERROR_NONE;
+
+    while (left > 0) {
+        if (left < CHUNK_SIZE)
+            size = left;
+
+        ret = ckmc_buffer_new(ptr, size, &in);
+        if (ret != CKMC_ERROR_NONE)
+            goto crypt_fail;
+
+        ret = ckmc_cipher_update(ctx, *in, &out);
+        if (ret != CKMC_ERROR_NONE)
+            goto crypt_fail;
+
+        ckmc_buffer_free(in);
+        in = nullptr;
+        if (out != nullptr)
+            std::copy(out->data, out->data + out->size, std::back_inserter(output));
+
+        ckmc_buffer_free(out);
+        out = nullptr;
+
+        left -= size;
+        ptr += size;
+    }
+
+crypt_fail:
+    ckmc_buffer_free(out);
+    ckmc_buffer_free(in);
+    return ret;
+}
+
+EncryptionError CipherApi::encrypt(ckmc_param_list_h params,
+                                   const char *key_alias,
+                                   const char *password,
+                                   const ckmc_raw_buffer_s& plain,
+                                   ckmc_raw_buffer_s **ppencrypted)
+{
+    ckmc_cipher_ctx_h ctx = nullptr;
+    size_t left = plain.size;
+    unsigned char* ptr = plain.data;
+    CKM::RawBuffer encrypted;
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* encrypted_c = nullptr;
+    uint64_t algo;
+
+    int ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ALGO_TYPE, &algo);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    // encrypt
+    ret = ckmc_cipher_initialize(params, key_alias, password, true, &ctx);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    ret = crypt(ctx, ptr, left, encrypted);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    ret = ckmc_cipher_finalize(ctx, nullptr, &out);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    // make sure finalize returns exactly the tag
+    if (algo == CKMC_ALGO_AES_GCM) {
+        uint64_t tagLen = 128;
+        ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ED_TAG_LEN, &tagLen);
+        if (ret != CKMC_ERROR_NONE && ret != CKMC_ERROR_INVALID_PARAMETER)
+            goto encrypt_fail;
+
+        if (tagLen / 8 != out->size) {
+            ret = CKMC_ERROR_SERVER_ERROR;
+            goto encrypt_fail;
+        }
+    }
+
+    if (out != nullptr)
+        std::copy(out->data, out->data + out->size, std::back_inserter(encrypted));
+    out = nullptr;
+
+    ret = ckmc_buffer_new(encrypted.data(), encrypted.size(), &encrypted_c);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    *ppencrypted = encrypted_c;
+
+encrypt_fail:
+    ckmc_buffer_free(out);
+    ckmc_cipher_free(ctx);
+
+    return ckmcError2Result(ret);
+}
+
+EncryptionError CipherApi::decrypt(ckmc_param_list_h params,
+                                   const char *key_alias,
+                                   const char *password,
+                                   const ckmc_raw_buffer_s& encrypted,
+                                   ckmc_raw_buffer_s **ppdecrypted)
+{
+    ckmc_cipher_ctx_h ctx = nullptr;
+    size_t left = encrypted.size;
+    unsigned char* ptr = encrypted.data;
+    CKM::RawBuffer decrypted;
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* decrypted_c = nullptr;
+    ckmc_raw_buffer_s* tag = nullptr;
+    uint64_t algo;
+
+    int ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ALGO_TYPE, &algo);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    // extract the tag to pass in finalize
+    if (algo == CKMC_ALGO_AES_GCM) {
+        uint64_t tagLen = 128;
+        ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ED_TAG_LEN, &tagLen);
+        if (ret != CKMC_ERROR_NONE && ret != CKMC_ERROR_INVALID_PARAMETER)
+            goto decrypt_fail;
+
+        tagLen /= 8;
+        if (tagLen > left) {
+            ret = CKMC_ERROR_INVALID_PARAMETER;
+            goto decrypt_fail;
+        }
+
+        ret = ckmc_buffer_new(encrypted.data + encrypted.size - tagLen, tagLen, &tag);
+        if (ret != CKMC_ERROR_NONE)
+            goto decrypt_fail;
+
+        left -= tagLen;
+    }
+
+    // decrypt
+    ret = ckmc_cipher_initialize(params, key_alias, password, false, &ctx);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    ret = crypt(ctx, ptr, left, decrypted);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    ret = ckmc_cipher_finalize(ctx, tag, &out);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    if (out != nullptr)
+        std::copy(out->data, out->data + out->size, std::back_inserter(decrypted));
+    out = nullptr;
+
+    ret = ckmc_buffer_new(decrypted.data(), decrypted.size(), &decrypted_c);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    *ppdecrypted = decrypted_c;
+
+decrypt_fail:
+    ckmc_cipher_free(ctx);
+    ckmc_buffer_free(out);
+    ckmc_buffer_free(tag);
+
+    return ckmcError2Result(ret);
+}
+
+EncryptionError CipherApi::ckmcError2Result(int error)
+{
+    switch (error) {
+    case CKMC_ERROR_NONE:                   return EncryptionError::SUCCESS;
+    case CKMC_ERROR_INVALID_PARAMETER:      return EncryptionError::INVALID_PARAM;
+    case CKMC_ERROR_SERVER_ERROR:           return EncryptionError::SERVER_ERROR;
+    case CKMC_ERROR_DB_ALIAS_UNKNOWN:       return EncryptionError::ALIAS_UNKNOWN;
+    case CKMC_ERROR_AUTHENTICATION_FAILED:  return EncryptionError::AUTH_FAILED;
+    default:                                return EncryptionError::OTHER;
+    }
+}
index 1af99e5..ac564f3 100644 (file)
@@ -35,7 +35,7 @@ enum EncryptionError{
     SERVER_ERROR,
     ALIAS_UNKNOWN,
     AUTH_FAILED,
-    OTHER,
+    OTHER
 };
 
 struct EncryptionApi
@@ -51,22 +51,26 @@ struct EncryptionApi
                                     const char *password,
                                     const ckmc_raw_buffer_s& encrypted,
                                     ckmc_raw_buffer_s **ppdecrypted) = 0;
+
+    virtual bool symmetricOnly() const { return false; }
+
+    virtual ~EncryptionApi() {}
 };
 
 class SyncApi : public EncryptionApi
 {
 public:
-    virtual EncryptionError encrypt(ckmc_param_list_h params,
-                                    const char *key_alias,
-                                    const char *password,
-                                    const ckmc_raw_buffer_s& decrypted,
-                                    ckmc_raw_buffer_s **ppencrypted);
+    EncryptionError encrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& decrypted,
+                            ckmc_raw_buffer_s **ppencrypted) override;
 
-    virtual EncryptionError decrypt(ckmc_param_list_h params,
-                                    const char *key_alias,
-                                    const char *password,
-                                    const ckmc_raw_buffer_s& encrypted,
-                                    ckmc_raw_buffer_s **ppdecrypted);
+    EncryptionError decrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& encrypted,
+                            ckmc_raw_buffer_s **ppdecrypted) override;
 private:
     static EncryptionError ckmcError2Result(int error);
 };
@@ -95,13 +99,13 @@ public:
                             const char *key_alias,
                             const char *password,
                             const ckmc_raw_buffer_s& decrypted,
-                            ckmc_raw_buffer_s **ppencrypted);
+                            ckmc_raw_buffer_s **ppencrypted) override;
 
     EncryptionError decrypt(ckmc_param_list_h params,
                             const char *key_alias,
                             const char *password,
                             const ckmc_raw_buffer_s& encrypted,
-                            ckmc_raw_buffer_s **ppdecrypted);
+                            ckmc_raw_buffer_s **ppdecrypted) override;
 private:
     typedef void (CKM::ManagerAsync::*cryptoFn)(const CKM::ManagerAsync::ObserverPtr&,
                                                 const CKM::CryptoAlgorithm&,
@@ -119,5 +123,25 @@ private:
     static EncryptionError ckmError2Result(int error);
 };
 
+class CipherApi : public EncryptionApi
+{
+public:
+    EncryptionError encrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& decrypted,
+                            ckmc_raw_buffer_s **ppencrypted) override;
+
+    EncryptionError decrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& encrypted,
+                            ckmc_raw_buffer_s **ppdecrypted) override;
+
+    bool symmetricOnly() const override { return true; }
 
+private:
+    int crypt(ckmc_cipher_ctx_h ctx, unsigned char *ptr, size_t left, CKM::RawBuffer& output);
+    EncryptionError ckmcError2Result(int error);
+};
 
index 037ff08..cf9e67a 100644 (file)
@@ -46,6 +46,7 @@ const size_t BUF_LEN = 86; // must be less than 1024/8-41 to support RSA OAEP 10
 // Environment
 SyncApi g_syncApi;
 AsyncApi g_asyncApi;
+CipherApi g_cipherApi;
 
 EncryptionApi* g_api = &g_syncApi;
 
@@ -134,6 +135,18 @@ struct AsyncEnv {
     static std::string suffix() { return "_async"; }
 };
 
+struct CipherEnv {
+    void init(const std::string&) {
+        g_api = &g_cipherApi;
+    }
+
+    void finish() {
+        g_api = nullptr;
+    }
+
+    static std::string suffix() { return "_cipher"; }
+};
+
 struct Algo {
     ckmc_algo_type_e type;
     size_t keyLen;
@@ -202,7 +215,7 @@ public:
 #ifdef TZ_BACKEND
         BIG_DATA = create_raw_buffer(createRandomBufferCAPI(1000));
 #else
-        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(5000000));
+        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(500000));
 #endif
         DEFAULT_IV = createRandomBufferCAPI(DEFAULT_IV_LEN);
         IV1 = createRandomBufferCAPI(1);
@@ -325,8 +338,7 @@ EncryptionResult encrypt(const Algo& algo,
     return ret;
 }
 
-void testAllAlgorithms(
-        const std::function<void(const Algo& algo)>& test)
+void testAllAlgorithms(const std::function<void(const Algo& algo)>& test)
 {
     test( { CKMC_ALGO_AES_CBC, 128 });
     test( { CKMC_ALGO_AES_CBC, 192 });
@@ -340,9 +352,12 @@ void testAllAlgorithms(
     test( { CKMC_ALGO_AES_CFB, 128 });
     test( { CKMC_ALGO_AES_CFB, 192 });
     test( { CKMC_ALGO_AES_CFB, 256 });
-    test( { CKMC_ALGO_RSA_OAEP, 1024 });
-    test( { CKMC_ALGO_RSA_OAEP, 2048 });
-    test( { CKMC_ALGO_RSA_OAEP, 4096 });
+
+    if (!g_api->symmetricOnly()) {
+        test( { CKMC_ALGO_RSA_OAEP, 1024 });
+        test( { CKMC_ALGO_RSA_OAEP, 2048 });
+        test( { CKMC_ALGO_RSA_OAEP, 4096 });
+    }
 }
 
 void testNoIvEnc(const Algo& algo)
@@ -919,6 +934,19 @@ void testRsaDataTooLong(const Algo& algo, size_t dataSize)
                          &encrypted);
 }
 
+std::pair<Alias, ParamListPtr> defaultGcmCipherSetup()
+{
+    Algo algo = {CKMC_ALGO_AES_GCM, 256};
+    KeyAliasPair aliases = getKey(algo, PRIMARY);
+
+    ckmc_param_list_h handle = NULL;
+    assert_positive(ckmc_generate_new_params, algo.type, &handle);
+    auto params = ParamListPtr(handle, ckmc_param_list_free);
+    setParam(params, CKMC_PARAM_ED_IV, IV12);
+
+    return std::make_pair(aliases.prv, params);
+}
+
 } // namespace anonymous
 
 RUNNER_TEST_GROUP_INIT_ENV(CKM_ENCRYPTION_DECRYPTION, EncGroupFixture);
@@ -927,7 +955,7 @@ RUNNER_TEST_GROUP_INIT_ENV(CKM_ENCRYPTION_DECRYPTION, EncGroupFixture);
 // Generic encryption decryption tests
 /////////////////////////////////////////
 
-RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -955,7 +983,7 @@ RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0020_encrypt_missing_key, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0020_encrypt_missing_key, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1026,7 +1054,7 @@ RUNNER_TEST_MULTIPLE(TED_0040_encrypt_no_output_buffer, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1054,7 +1082,7 @@ RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0120_decrypt_missing_key, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0120_decrypt_missing_key, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1117,7 +1145,7 @@ RUNNER_TEST_MULTIPLE(TED_0140_decrypt_no_output_buffer, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_GCM, 128}, false);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_GCM, 192}, false);
@@ -1128,12 +1156,15 @@ RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv)
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 128}, true);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 192}, true);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 256}, true);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 1024}, false);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 2048}, false);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 4096}, false);
+
+    if (!g_api->symmetricOnly()) {
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 1024}, false);
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 2048}, false);
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 4096}, false);
+    }
 }
 
-RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1154,7 +1185,7 @@ RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1186,62 +1217,62 @@ RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv)
 }
 
 // long test split into smaller ones
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 256});
 }
@@ -1250,7 +1281,7 @@ RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, Asy
 // Algorithm specific tests
 /////////////////////////////////////////
 
-RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv, CipherEnv)
 {
     testNoIvEnc({CKMC_ALGO_AES_CTR, 128});
     testNoIvEnc({CKMC_ALGO_AES_CTR, 192});
@@ -1266,7 +1297,7 @@ RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv)
     testNoIvEnc({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv, CipherEnv)
 {
     testInvalidIvEnc({CKMC_ALGO_AES_CTR, 128});
     testInvalidIvEnc({CKMC_ALGO_AES_CTR, 192});
@@ -1279,7 +1310,7 @@ RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv)
     testInvalidIvEnc({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv, CipherEnv)
 {
     testNoIvDec({CKMC_ALGO_AES_CTR, 128});
     testNoIvDec({CKMC_ALGO_AES_CTR, 192});
@@ -1295,7 +1326,7 @@ RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv)
     testNoIvDec({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv, CipherEnv)
 {
     testInvalidIvDec({CKMC_ALGO_AES_CTR, 128});
     testInvalidIvDec({CKMC_ALGO_AES_CTR, 192});
@@ -1308,7 +1339,7 @@ RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv)
     testInvalidIvDec({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv, CipherEnv)
 {
     testIntegrity({CKMC_ALGO_AES_CTR, 128});
     testIntegrity({CKMC_ALGO_AES_CTR, 192});
@@ -1321,14 +1352,14 @@ RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv)
     testIntegrity({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1100_ctr_encryption_invalid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1100_ctr_encryption_invalid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 128});
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 192});
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     RUNNER_IGNORED_MSG("Openssl supports only 128-bit AES CTR length");
     testCtrEncryptionValidLength({CKMC_ALGO_AES_CTR, 128});
@@ -1336,14 +1367,14 @@ RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv)
     testCtrEncryptionValidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1110_ctr_decryption_invalid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1110_ctr_decryption_invalid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 128});
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 192});
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     RUNNER_IGNORED_MSG("Openssl supports only 128-bit AES CTR length");
     testCtrDecryptionValidLength({CKMC_ALGO_AES_CTR, 128});
@@ -1351,35 +1382,35 @@ RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv)
     testCtrDecryptionValidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1200_gcm_encryption_tag_len, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1200_gcm_encryption_tag_len, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 128});
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 192});
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1210_gcm_decryption_tag_len, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1210_gcm_decryption_tag_len, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 128});
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 192});
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1230_gcm_wrong_tag, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1230_gcm_wrong_tag, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 128});
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 192});
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1240_gcm_different_iv_sizes, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1240_gcm_different_iv_sizes, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 128});
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 192});
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1250_gcm_aad, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1250_gcm_aad, SyncEnv, AsyncEnv, CipherEnv)
 {
     encryptionWithCustomData({CKMC_ALGO_AES_GCM, 128}, CKMC_PARAM_ED_AAD);
     encryptionWithCustomData({CKMC_ALGO_AES_GCM, 192}, CKMC_PARAM_ED_AAD);
@@ -1454,7 +1485,7 @@ RUNNER_TEST(TED_2010_dec_no_observer_async, AsyncEnv)
 /////////////////////////////////////////
 // Mulithreaded test for synchronous API
 /////////////////////////////////////////
-RUNNER_TEST(TED_3000_muliple_threads, SyncEnv)
+RUNNER_TEST_MULTIPLE(TED_3000_multiple_threads, SyncEnv, CipherEnv)
 {
     std::vector<std::thread> threads;
     threads.reserve(10);
@@ -1463,3 +1494,154 @@ RUNNER_TEST(TED_3000_muliple_threads, SyncEnv)
     for (auto& thread : threads)
         thread.join();
 }
+
+/////////////////////////////////////////
+// Cipher API only
+/////////////////////////////////////////
+RUNNER_TEST(TED_4000_cipher_missing_arguments)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // no AAD
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+
+    // missing arguments
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+    assert_invalid_param(ckmc_cipher_update, nullptr, *PLAIN_DATA.get(), &encrypted);
+    assert_invalid_param(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), nullptr);
+    assert_invalid_param(ckmc_cipher_finalize, nullptr, nullptr, &encrypted);
+    assert_invalid_param(ckmc_cipher_finalize, nullptr, nullptr, nullptr);
+}
+
+RUNNER_TEST(TED_4010_cipher_reinitialize_without_aad)
+{
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // no AAD
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+}
+
+RUNNER_TEST(TED_4020_cipher_tag_during_encryption)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // tag input during encryption
+    assert_invalid_param(ckmc_cipher_finalize, ctx, PLAIN_DATA.get(), &encrypted);
+}
+
+RUNNER_TEST(TED_4030_cipher_wrong_order)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+    ckmc_buffer_free(encrypted);
+
+    // initialize after update
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+
+    assert_positive(ckmc_cipher_finalize, ctx, nullptr, &encrypted);
+    ckmc_buffer_free(encrypted);
+
+    // initialize after finalize
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+
+    // update after finalize
+    assert_invalid_param(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+}
+
+RUNNER_TEST(TED_4040_cipher_gcm_aad_and_tag)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+
+    // encrypt
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // 2 more AAD chunks
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+
+    ckmc_raw_buffer_s* tag = nullptr;
+
+    assert_positive(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+    auto encryptedPtr = create_raw_buffer(encrypted);
+    assert_positive(ckmc_cipher_finalize, ctx, nullptr, &tag);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    ckmc_raw_buffer_s* decrypted = nullptr;
+    ckmc_raw_buffer_s* empty = nullptr;
+
+    // decrypt with invalid AAD
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    ckmc_buffer_free(decrypted);
+    assert_invalid_param(ckmc_cipher_finalize, ctx, tag, &empty);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    // decrypt without TAG
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    ckmc_buffer_free(decrypted);
+    assert_invalid_param(ckmc_cipher_finalize, ctx, nullptr, &empty);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    // correct decrypt
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    auto decryptedPtr = create_raw_buffer(decrypted);
+    assert_positive(ckmc_cipher_finalize, ctx, tag, &empty);
+
+    RUNNER_ASSERT(empty == nullptr);
+
+    assert_buffers_equal(PLAIN_DATA.get(), decrypted);
+}