CKM: Max chunk size test
[platform/core/test/security-tests.git] / src / ckm / unprivileged / encryption-decryption-env.cpp
index 03dc266..7f43bcb 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <encryption-decryption-env.h>
+#include <ckm-common.h>
 
 using namespace CKM;
 
@@ -145,3 +146,196 @@ 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)
+{
+#ifdef TZ_BACKEND
+    ckmc_backend_info_h info;
+    size_t maxSize;
+    // All unexportable keys go to TZ if enabled (and all of them are unexportable)
+    assert_positive(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+    assert_positive(ckmc_backend_get_max_chunk_size, info, &maxSize);
+    const size_t CHUNK_SIZE = 80 < maxSize ? 80 : maxSize;
+#else
+    const size_t CHUNK_SIZE = 80;
+#endif
+    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;
+    }
+}