Add Security Keys backend implementation 31/319331/33
authorJakub Wlostowski <j.wlostowski@samsung.com>
Fri, 7 Feb 2025 12:05:21 +0000 (13:05 +0100)
committerDariusz Michaluk <d.michaluk@samsung.com>
Mon, 24 Mar 2025 17:48:57 +0000 (18:48 +0100)
Change-Id: I689809900c8d83f87a47df0b2a54fdee3b36bc66

13 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
packaging/hal-backend-security-keys.manifest [new file with mode: 0644]
packaging/hal-backend-security-keys.spec [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/crypto-params.h [new file with mode: 0644]
src/hal-backend-security-keys-api.cpp [new file with mode: 0644]
src/log.cpp [new file with mode: 0644]
src/log.h [new file with mode: 0644]
src/tz-memory.cpp [new file with mode: 0644]
src/tz-memory.h [new file with mode: 0644]
src/tz-serializer.cpp [new file with mode: 0644]
src/tz-serializer.h [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4c9145f
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    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.
+#
+
+PROJECT(hal-backend-security-keys LANGUAGES C CXX)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
+
+INCLUDE(GNUInstallDirs)
+INCLUDE(CheckLibraryExists)
+
+IF(NOT CMAKE_BUILD_TYPE)
+       SET(CMAKE_BUILD_TYPE "RELEASE")
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+SET(CMAKE_C_FLAGS_DEBUG        "-std=c11 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_CXX_FLAGS_DEBUG      "-std=c++17 -O0 -ggdb -Wp,-U_FORTIFY_SOURCE")
+SET(CMAKE_C_FLAGS_RELEASE      "-std=c11 -O2 -DNDEBUG")
+SET(CMAKE_CXX_FLAGS_RELEASE    "-std=c++17 -O2 -DNDEBUG")
+
+ADD_DEFINITIONS("-Werror -Wall -Wextra")
+
+SET(CMAKE_POSITION_INDEPENDENT_CODE "True")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie")
+
+ADD_SUBDIRECTORY(src)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..9f8d261
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/packaging/hal-backend-security-keys.manifest b/packaging/hal-backend-security-keys.manifest
new file mode 100644 (file)
index 0000000..50eefc9
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
\ No newline at end of file
diff --git a/packaging/hal-backend-security-keys.spec b/packaging/hal-backend-security-keys.spec
new file mode 100644 (file)
index 0000000..fb0d8b5
--- /dev/null
@@ -0,0 +1,40 @@
+Name: hal-backend-security-keys
+Summary: Security Keys (based on key-manager-ta and tef-simulator) backend library
+Version: 1.0.0
+Release: 0
+Group: Security/Development
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Source1001: hal-backend-security-keys.manifest
+BuildRequires: cmake
+BuildRequires: pkgconfig(hal-rootstrap)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+# FIXME
+BuildRequires: key-manager-ta-devel
+BuildRequires: key-manager-ta-serialization-devel
+BuildRequires: pkgconfig(tef-libteec)
+# Disable hal-rootstrap-checker in order to use key-manager-ta
+%define disable_hal_rootstrap_checker 1
+
+%description
+Security Keys (based on key-manager-ta and tef-simulator) backend library
+
+%prep
+%setup -q
+cp -a %{SOURCE1001} .
+
+%build
+%cmake . -DHAL_LIB_DIR=%{_hal_libdir} \
+         -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:Release}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+%files
+%manifest hal-backend-security-keys.manifest
+%license LICENSE
+%{_hal_libdir}/lib%{name}.so*
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a0181f5
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    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.
+#
+
+PROJECT(hal-backend-security-keys LANGUAGES C CXX)
+SET(PROJECT_VERSION "1.0.0")
+
+SET(_LIB_VERSION_ "${PROJECT_VERSION}")
+SET(_LIB_SOVERSION_ "0")
+
+FIND_PACKAGE(PkgConfig REQUIRED)
+PKG_CHECK_MODULES(ROOTSTRAP REQUIRED hal-rootstrap)
+
+INCLUDE_DIRECTORIES(SYSTEM ${ROOTSTRAP_INCLUDE_DIRS})
+LINK_DIRECTORIES(${ROOTSTRAP_LIBRARY_DIRS})
+
+# FIXME
+PKG_CHECK_MODULES(SECURITY_KEYS_DEPS REQUIRED tef-libteec)
+INCLUDE_DIRECTORIES(SYSTEM ${SECURITY_KEYS_DEPS_INCLUDE_DIRS})
+LINK_DIRECTORIES(${SECURITY_KEYS_DEPS_LIBRARY_DIRS})
+SET(KM_LINK_EXTRA_DEPS km_serialization)
+
+ADD_LIBRARY(${PROJECT_NAME} SHARED
+       hal-backend-security-keys-api.cpp
+       tz-memory.cpp
+       tz-serializer.cpp
+       log.cpp)
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${ROOTSTRAP_LIBRARIES} -ldlog
+       ${SECURITY_KEYS_DEPS_LIBRARIES} ${KM_LINK_EXTRA_DEPS})
+
+SET_TARGET_PROPERTIES(${PROJECT_NAME}
+       PROPERTIES
+       VERSION ${_LIB_VERSION_}
+       SOVERSION ${_LIB_SOVERSION_}
+       VISIBILITY_INLINES_HIDDEN TRUE
+       C_VISIBILITY_PRESET hidden
+       CXX_VISIBILITY_PRESET hidden)
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${HAL_LIB_DIR} COMPONENT RuntimeLibraries)
diff --git a/src/crypto-params.h b/src/crypto-params.h
new file mode 100644 (file)
index 0000000..4dcee71
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+class Params
+{
+public:
+       static const uint32_t DEFAULT_AES_IV_LEN = 16; // max acceptable size of IV
+       static const int DEFAULT_AES_GCM_TAG_LEN_BYTES = 16; // length of AES GCM tag
+       static const int DEFAULT_AES_GCM_TAG_LEN_BITS = DEFAULT_AES_GCM_TAG_LEN_BYTES * 8;
+       static const int DERIVED_KEY_LENGTH = 16; // length of AES key derived from password in bytes
+       static const int DERIVED_KEY_LENGTH_BITS = DERIVED_KEY_LENGTH * 8; // as above, in bits
+       static const int DERIVED_KEY_ITERATIONS = 1024; // iteration count used to derive key
+       static const uint32_t CIPHER_EXTRA_PADDING_SIZE = 16; //extra memory to add to output buffers for padding purposes
+};
\ No newline at end of file
diff --git a/src/hal-backend-security-keys-api.cpp b/src/hal-backend-security-keys-api.cpp
new file mode 100644 (file)
index 0000000..6de8b51
--- /dev/null
@@ -0,0 +1,1845 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <cstring>
+#include <functional>
+#include <stdexcept>
+#include <string>
+
+#include <hal/hal-common-interface.h>
+#include <hal/hal-security-keys-interface.h>
+#include <hal/hal-security-keys-types.h>
+#include <km_ta_defines.h>
+#include <tee_client_api.h>
+
+#include "crypto-params.h"
+#include "log.h"
+#include "tz-memory.h"
+#include "tz-serializer.h"
+
+#define EXPORT __attribute__ ((visibility("default")))
+
+namespace {
+
+// Identifier of our key-manager TA
+const TEEC_UUID KEY_MANAGER_TA_UUID = KM_TA_UUID;
+
+tz_algo_type to_tz_algo_type(hal_security_keys_algo_type_e type)
+{
+       switch (type) {
+               case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CTR:  return ALGO_AES_CTR;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CBC:  return ALGO_AES_CBC;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_AES_GCM:  return ALGO_AES_GCM;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_AES_CFB:  return ALGO_AES_CFB;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_RSA_OAEP: return ALGO_RSA;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_RSA:      return ALGO_RSA_SV;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_DSA:      return ALGO_DSA_SV;
+               case HAL_SECURITY_KEYS_ALGO_TYPE_ECDSA:    return ALGO_ECDSA_SV;
+               default:
+                       throw std::invalid_argument("Requested algorithm is not supported");
+       }
+}
+
+tz_ec to_tz_ec_type(hal_security_keys_ec_type_e ec)
+{
+       switch (ec) {
+               case HAL_SECURITY_KEYS_EC_TYPE_PRIME192V1: return EC_NIST_P192;
+               case HAL_SECURITY_KEYS_EC_TYPE_PRIME256V1: return EC_NIST_P256;
+               case HAL_SECURITY_KEYS_EC_TYPE_SECP384R1:  return EC_NIST_P384;
+               default:
+                       throw std::invalid_argument("EC not supported by tz-backend");
+       }
+}
+
+tz_kem to_tz_kem_type(hal_security_keys_kem_type_e kem)
+{
+       switch (kem) {
+               case HAL_SECURITY_KEYS_ML_KEM_768: return ML_KEM_768;
+               case HAL_SECURITY_KEYS_ML_KEM_1024: return ML_KEM_1024;
+               default:
+                       throw std::invalid_argument("KEM not supported by tz-backend");
+       }
+}
+
+tz_data_type to_tz_data_type(hal_security_keys_data_type_e type)
+{
+       switch (type) {
+               case HAL_SECURITY_KEYS_DATA_TYPE_BINARY_DATA:       return TYPE_GENERIC_SECRET;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_AES:           return TYPE_SKEY;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_RSA_PUBLIC:    return TYPE_AKEY_PUBLIC_RSA;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_RSA_PRIVATE:   return TYPE_AKEY_PRIVATE_RSA;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_DSA_PUBLIC:    return TYPE_AKEY_PUBLIC_DSA;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_DSA_PRIVATE:   return TYPE_AKEY_PRIVATE_DSA;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_ECDSA_PUBLIC:  return TYPE_AKEY_PUBLIC_EC;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_ECDSA_PRIVATE: return TYPE_AKEY_PRIVATE_EC;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_KEM_PUBLIC:    return TYPE_AKEY_PUBLIC_KEM;
+               case HAL_SECURITY_KEYS_DATA_TYPE_KEY_KEM_PRIVATE:   return TYPE_AKEY_PRIVATE_KEM;
+               default:
+                       throw std::invalid_argument("Data type not supported by tz-backend");
+       }
+}
+
+tz_hash_type to_tz_hash_type(hal_security_keys_hash_algorithm_e hash)
+{
+       switch (hash) {
+               case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA1:   return HASH_SHA1;
+               case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA256: return HASH_SHA256;
+               case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA384: return HASH_SHA384;
+               case HAL_SECURITY_KEYS_HASH_ALGORITHM_SHA512: return HASH_SHA512;
+               default:
+                       throw std::invalid_argument("Requested hash algorithm is not supported");
+       }
+}
+
+tz_prf to_tz_prf(hal_security_keys_kdf_prf_type_e prf)
+{
+       switch (prf) {
+               case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA256: return PRF_HMAC_SHA256;
+               case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA384: return PRF_HMAC_SHA384;
+               case HAL_SECURITY_KEYS_PRF_TYPE_HMAC_SHA512: return PRF_HMAC_SHA512;
+               default:
+                       throw std::invalid_argument("PRF not supported by tz-backend");
+       }
+}
+
+tz_kbkdf_mode to_tz_kbkdf_mode(hal_security_keys_kbkdf_mode_e mode)
+{
+       switch (mode) {
+               case HAL_SECURITY_KEYS_KBKDF_MODE_COUNTER: return KBKDF_MODE_COUNTER;
+               default:
+                       throw std::invalid_argument("KBKDF mode not supported by tz-backend");
+       }
+}
+
+tz_kbkdf_ctr_loc to_tz_kbkdf_ctr_loc(hal_security_keys_kbkdf_counter_location_e loc)
+{
+       switch (loc) {
+               case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_BEFORE_FIXED: return KBKDF_LOC_BEFORE_FIXED;
+               case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_AFTER_FIXED:  return KBKDF_LOC_AFTER_FIXED;
+               case HAL_SECURITY_KEYS_KBKDF_COUNTER_LOCATION_MIDDLE_FIXED: return KBKDF_LOC_MIDDLE_FIXED;
+               default:
+                       throw std::invalid_argument("KBKDF counter location not supported by tz-backend");
+       }
+}
+
+//Maximum size for given key type in bytes according to key-manager-ta implementation.
+//Note that they are greater than TEE Internal Core API v1.1.2.50 (Table 5-9) values.
+size_t get_tz_max_key_size(tz_algo_type type)
+{
+       switch (type) {
+               case ALGO_RSA:
+               case ALGO_RSA_SV:
+               case ALGO_DSA_SV:
+                       return 4096 / 8;
+               case ALGO_ECDSA_SV:
+                       return 1024 / 8; // 384*2 + additional space for DER encoding
+               default:
+                       throw std::invalid_argument("Algorithm not supported by tz-backend");
+       }
+}
+
+template <class T, bool uppercase = false>
+T hex_dump(const hal_security_keys_data_s &raw)
+{
+       T dump;
+
+       if (!raw.buffer)
+               return dump;
+
+       dump.reserve(2 * raw.length);
+       constexpr char digit[2][16] = {{
+               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+               'a', 'b', 'c', 'd', 'e', 'f'
+       }, {
+               '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+               'A', 'B', 'C', 'D', 'E', 'F'
+       }};
+
+       for (size_t i = 0; i < raw.length; ++i) {
+               dump.push_back(digit[uppercase][raw.buffer[i] / 16]);
+               dump.push_back(digit[uppercase][raw.buffer[i] % 16]);
+       }
+
+       return dump;
+}
+
+static std::string raw_to_hex_string(const hal_security_keys_data_s &raw)
+{
+       return hex_dump<std::string>(raw);
+}
+
+int try_catch(const std::function<int()> &func)
+{
+       try {
+               return func();
+       } catch (const std::invalid_argument &e) {
+               LOGE("Invalid parameter: " << e.what());
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+       } catch (const std::bad_alloc &e) {
+               LOGE("Memory allocation exception: " << e.what());
+               return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY;
+       } catch (const std::exception &e) {
+               LOGE("Exception occurred: " << e.what());
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       } catch (...) {
+               LOGE("Unknown exception occurred.");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+}
+
+#define EXCEPTION_GUARD_START  return try_catch([&]()->int {
+#define EXCEPTION_GUARD_END            });
+
+#define CHECK_RET(func) do { int ret = (func); if (ret) return ret; } while (0)
+
+template <typename T>
+void push(TZSerializer& ser, const T& value)
+{
+       ser.Push(new TZSerializableFlag(static_cast<uint32_t>(value)));
+}
+
+template<>
+void push<hal_security_keys_data_s>(TZSerializer& ser, const hal_security_keys_data_s& value)
+{
+       ser.Push(new TZSerializableBinary(value));
+}
+
+template<>
+void push<hal_security_keys_password_iv_s>(TZSerializer& ser, const hal_security_keys_password_iv_s& value)
+{
+       int32_t with_pwd = !value.password.buffer ? 0 : 1;
+       ser.Push(new TZSerializableFlag(with_pwd));
+       if (with_pwd)
+               ser.Push(new TZSerializablePwdData(value.password, value.iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
+}
+
+template<>
+void push<hal_security_keys_password_iv_tag_s>(TZSerializer& ser, const hal_security_keys_password_iv_tag_s& value)
+{
+       int32_t with_pwd = !value.password.buffer ? 0 : 1;
+       ser.Push(new TZSerializableFlag(with_pwd));
+       if (with_pwd)
+               ser.Push(new TZSerializablePwdData(value.password,
+                                                                                  value.iv,
+                                                                                  value.tag.length * 8,
+                                                                                  value.tag));
+}
+
+template <typename T, typename ...Args>
+void push(TZSerializer& ser, const T& first, const Args&... args)
+{
+       push<T>(ser, first);
+       push<Args...>(ser, args...);
+}
+
+template <typename ...Args>
+TZSerializer makeSerializer(const Args&... args)
+{
+       TZSerializer ser;
+       push<Args...>(ser, args...);
+       return ser;
+}
+
+TEEC_Operation make_op(uint32_t value, TrustZoneMemory& mem1)
+{
+       TEEC_Operation op;
+
+       op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_NONE, TEEC_NONE);
+
+       op.params[1].memref.parent = mem1.Get();
+       op.params[1].memref.offset = 0;
+       op.params[1].memref.size = mem1.Get()->size;
+       return op;
+}
+
+TEEC_Operation make_op(uint32_t value, TrustZoneMemory& mem1, TrustZoneMemory& mem2)
+{
+       TEEC_Operation op = make_op(value, mem1);
+
+       op.paramTypes = TEEC_PARAM_TYPES(value, TEEC_MEMREF_WHOLE, TEEC_MEMREF_WHOLE, TEEC_NONE);
+
+       op.params[2].memref.parent = mem2.Get();
+       op.params[2].memref.offset = 0;
+       op.params[2].memref.size = mem2.Get()->size;
+
+       return op;
+}
+
+int execute(tz_command command_id, TEEC_Operation* op, TEEC_Session tz_session)
+{
+       uint32_t ret = 0;
+       LOGD("Executing TZ operation " << command_id);
+
+       TEEC_Result result = TEEC_InvokeCommand(&tz_session, static_cast<unsigned int>(command_id), op, &ret);
+       if (result != TEEC_SUCCESS) {
+               switch (result) {
+                       case TEEC_ERROR_TARGET_DEAD:
+                               LOGE("TA panicked while executing command " << static_cast<unsigned int>(command_id));
+                               return HAL_SECURITY_KEYS_ERROR_TARGET_DEAD;
+                       case TEEC_ERROR_BAD_PARAMETERS:
+                               LOGE("Incorrect parameters provided to TA");
+                               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+                       default:
+                               LOGE("TA failed to invoke command " <<
+                                               static_cast<unsigned int>(command_id) << " with error: " << std::hex <<
+                                               static_cast<unsigned int>(result) << " with origin: " << std::hex << ret);
+                               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+               }
+       }
+
+       int ta_ret = op->params[0].value.a;
+       switch (ta_ret) {
+               case KM_TA_SUCCESS:
+               case KM_TA_ERROR_SIGNATURE:
+                       return HAL_SECURITY_KEYS_ERROR_NONE;
+               case KM_TA_ERROR_AUTH_FAILED:
+                       LOGE("Crypto operation authentication failed");
+                       return HAL_SECURITY_KEYS_ERROR_AUTHENTICATION_FAILED;
+               default:
+                       LOGE("Unknown TA error during operation: " << ta_ret);
+                       return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+}
+
+} // anonymous namespace
+
+int security_keys_context_initialize(hal_security_keys_context_s* context)
+{
+       EXCEPTION_GUARD_START
+       LOGD("security_keys_context_initialize");
+
+       if (!context)
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+
+       TEEC_Context* tz_context = new TEEC_Context;
+       TEEC_Session* tz_session = new TEEC_Session;
+       if (!tz_context || !tz_session)
+               return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY;
+
+       TEEC_Operation op;
+       TEEC_Result result;
+       uint32_t ret;
+
+       op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+       result = TEEC_InitializeContext(nullptr, tz_context);
+       if (result != TEEC_SUCCESS) {
+               LOGE("Failed to initialize context: " << result);
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+       context->ctx = (void *)tz_context;
+
+       result = TEEC_OpenSession(tz_context, tz_session, &KEY_MANAGER_TA_UUID, 0, nullptr, &op, &ret);
+       if (result != TEEC_SUCCESS) {
+               LOGE("Failed to open session to Key Manager TA: " << result);
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+       context->session = (void *)tz_session;
+
+       LOGD("Initialized context");
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_context_free(hal_security_keys_context_s* context)
+{
+       EXCEPTION_GUARD_START
+       LOGD("security_keys_context_free");
+
+       if (!context)
+               return 0;
+
+       if (context->session) {
+               TEEC_Session* tz_session = static_cast<TEEC_Session*>(context->session);
+               TEEC_CloseSession(tz_session);
+               delete static_cast<TEEC_Session*>(context->session);
+               context->session = nullptr;
+       }
+
+       if (context->ctx) {
+               TEEC_Context* tz_context = static_cast<TEEC_Context*>(context->ctx);
+               TEEC_FinalizeContext(tz_context);
+               delete static_cast<TEEC_Context*>(context->ctx);
+               context->ctx = nullptr;
+       }
+
+       LOGD("Destroyed context");
+
+       return 0;
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_iv(const hal_security_keys_context_s context,
+                                                       hal_security_keys_data_s* iv)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GENERATE_IV
+       LOGD("security_keys_create_iv");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       TrustZoneMemory iv_memory(*tz_context, Params::DEFAULT_AES_IV_LEN, TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, iv_memory);
+
+       CHECK_RET(execute(CMD_GENERATE_IV, &op, *tz_session));
+
+       iv->buffer = (unsigned char*)malloc(iv_memory.Get()->size);
+       if (!(iv->buffer)) {
+               LOGE("Failed to allocate memory for IV");
+               return HAL_SECURITY_KEYS_ERROR_OUT_OF_MEMORY;
+       }
+
+       memcpy(iv->buffer, iv_memory.Get()->buffer, iv_memory.Get()->size);
+       iv->length = iv_memory.Get()->size;
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_key_aes(const hal_security_keys_context_s context,
+                                                                const size_t key_size_bits,
+                                                                const hal_security_keys_data_s key_id,
+                                                                const hal_security_keys_password_iv_s key_pwd,
+                                                                hal_security_keys_data_s* key_tag)
+{
+       EXCEPTION_GUARD_START
+       LOGD("security_keys_create_key_aes");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       bool with_pwd = !key_pwd.password.buffer ? 0 : 1;
+       if (with_pwd) {
+               // command ID = CMD_GENERATE_KEY_PWD
+               TZSerializer s_in;
+               s_in.Push(new TZSerializablePwdData(key_pwd.password, key_pwd.iv, Params::DEFAULT_AES_GCM_TAG_LEN_BITS));
+               s_in.Push(new TZSerializableBinary(key_id));
+               TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+               s_in.Serialize(in_memory);
+
+               TZSerializer s_out;
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+               TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+               TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+               op.params[0].value.a = ALGO_AES_GEN;
+               op.params[0].value.b = key_size_bits;
+
+               CHECK_RET(execute(CMD_GENERATE_KEY_PWD, &op, *tz_session));
+
+               s_out.Deserialize(out_memory);
+               s_out.Pull(key_tag);
+
+               if (key_tag->length != Params::DEFAULT_AES_GCM_TAG_LEN_BYTES) {
+                       LOGE("Deserialized incorrect key tag");
+                       return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+               }
+
+               return 0;
+       } else {
+               // command ID = CMD_GENERATE_KEY
+               TZSerializer s_in;
+               s_in.Push(new TZSerializableBinary(key_id));
+               TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+               s_in.Serialize(in_memory);
+
+               TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+               op.params[0].value.a = ALGO_AES_GEN;
+               op.params[0].value.b = key_size_bits;
+
+               return execute(CMD_GENERATE_KEY, &op, *tz_session);
+       }
+
+       EXCEPTION_GUARD_END
+}
+
+int create_asym_key_pair(const hal_security_keys_context_s context,
+                                                tz_command command_id,
+                                                TZSerializer &s_in,
+                                                uint32_t gen_param, // key size in bits or type
+                                                const hal_security_keys_data_s priv_key_id,
+                                                const hal_security_keys_password_iv_s priv_key_pwd,
+                                                const hal_security_keys_data_s pub_key_id,
+                                                const hal_security_keys_password_iv_s pub_key_pwd,
+                                                hal_security_keys_data_s* priv_key_tag,
+                                                hal_security_keys_data_s* pub_key_tag)
+{
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       bool with_pub_pwd = !pub_key_pwd.password.buffer ? 0 : 1;
+       TZSerializer s_out;
+       if (with_pub_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       bool with_priv_pwd = !priv_key_pwd.password.buffer ? 0 : 1;
+       if (with_priv_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       push(s_in, pub_key_pwd, priv_key_pwd, priv_key_id, pub_key_id);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op;
+       if (s_out.GetSize() == 0)
+               op = make_op(TEEC_VALUE_INOUT, in_memory);
+       else
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       op.params[0].value.b = gen_param;
+
+       CHECK_RET(execute(command_id, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       if (with_pub_pwd)
+               s_out.Pull(pub_key_tag);
+
+       if (with_priv_pwd)
+               s_out.Pull(priv_key_tag);
+
+       return 0;
+}
+
+int security_keys_create_key_pair_rsa(const hal_security_keys_context_s context,
+                                                                         const size_t key_size_bits,
+                                                                         const hal_security_keys_data_s priv_key_id,
+                                                                         const hal_security_keys_password_iv_s priv_key_pwd,
+                                                                         const hal_security_keys_data_s pub_key_id,
+                                                                         const hal_security_keys_password_iv_s pub_key_pwd,
+                                                                         hal_security_keys_data_s* priv_key_tag,
+                                                                         hal_security_keys_data_s* pub_key_tag)
+
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GENERATE_RSA_KEYPAIR
+       LOGD("security_keys_create_key_pair_rsa");
+
+       TZSerializer s_in;
+       return create_asym_key_pair(context, CMD_GENERATE_RSA_KEYPAIR,
+                                                               s_in, key_size_bits,
+                                                               priv_key_id, priv_key_pwd,
+                                                               pub_key_id, pub_key_pwd,
+                                                               priv_key_tag, pub_key_tag);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_key_pair_dsa(const hal_security_keys_context_s context,
+                                                                         const size_t key_size_bits,
+                                                                         const hal_security_keys_data_s prime,
+                                                                         const hal_security_keys_data_s subprime,
+                                                                         const hal_security_keys_data_s base,
+                                                                         const hal_security_keys_data_s priv_key_id,
+                                                                         const hal_security_keys_password_iv_s priv_key_pwd,
+                                                                         const hal_security_keys_data_s pub_key_id,
+                                                                         const hal_security_keys_password_iv_s pub_key_pwd,
+                                                                         hal_security_keys_data_s* priv_key_tag,
+                                                                         hal_security_keys_data_s* pub_key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GENERATE_DSA_KEYPAIR
+       LOGD("security_keys_create_key_pair_dsa");
+
+       auto s_in = makeSerializer(prime, subprime, base);
+       return create_asym_key_pair(context, CMD_GENERATE_DSA_KEYPAIR,
+                                                               s_in, key_size_bits,
+                                                               priv_key_id, priv_key_pwd,
+                                                               pub_key_id, pub_key_pwd,
+                                                               priv_key_tag, pub_key_tag);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_key_pair_ecdsa(const hal_security_keys_context_s context,
+                                                                               const hal_security_keys_ec_type_e ec_type,
+                                                                               const hal_security_keys_data_s priv_key_id,
+                                                                               const hal_security_keys_password_iv_s priv_key_pwd,
+                                                                               const hal_security_keys_data_s pub_key_id,
+                                                                               const hal_security_keys_password_iv_s pub_key_pwd,
+                                                                               hal_security_keys_data_s* priv_key_tag,
+                                                                               hal_security_keys_data_s* pub_key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GENERATE_EC_KEYPAIR
+       LOGD("security_keys_create_key_pair_ecdsa");
+
+       auto tz_ec_type = to_tz_ec_type(ec_type);
+
+       TZSerializer s_in;
+       return create_asym_key_pair(context, CMD_GENERATE_EC_KEYPAIR,
+                                                               s_in, tz_ec_type,
+                                                               priv_key_id, priv_key_pwd,
+                                                               pub_key_id, pub_key_pwd,
+                                                               priv_key_tag, pub_key_tag);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_key_pair_kem(const hal_security_keys_context_s context,
+                                                                         const hal_security_keys_kem_type_e kem_type,
+                                                                         const hal_security_keys_data_s priv_key_id,
+                                                                         const hal_security_keys_password_iv_s priv_key_pwd,
+                                                                         const hal_security_keys_data_s pub_key_id,
+                                                                         const hal_security_keys_password_iv_s pub_key_pwd,
+                                                                         hal_security_keys_data_s* priv_key_tag,
+                                                                         hal_security_keys_data_s* pub_key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GENERATE_KEM_KEYPAIR
+       LOGD("security_keys_create_key_pair_kem");
+
+       auto tz_kem_type = to_tz_kem_type(kem_type);
+
+       TZSerializer s_in;
+       return create_asym_key_pair(context, CMD_GENERATE_KEM_KEYPAIR,
+                                                               s_in, tz_kem_type,
+                                                               priv_key_id, priv_key_pwd,
+                                                               pub_key_id, pub_key_pwd,
+                                                               priv_key_tag, pub_key_tag);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_import_wrapped_key(const hal_security_keys_context_s context,
+                                                                        const hal_security_keys_algo_type_e algo,
+                                                                        const hal_security_keys_hash_algorithm_e hash,
+                                                                        const hal_security_keys_data_s iv,
+                                                                        const hal_security_keys_data_s aad,
+                                                                        const size_t ctr_len_or_tag_size_bits,
+                                                                        const hal_security_keys_data_s wrapping_key_id,
+                                                                        const hal_security_keys_password_iv_tag_s wrapping_key_pwd,
+                                                                        const hal_security_keys_data_s wrapped_key,
+                                                                        const hal_security_keys_data_s key_id,
+                                                                        const hal_security_keys_password_iv_s key_pwd,
+                                                                        const hal_security_keys_data_type_e key_type,
+                                                                        hal_security_keys_data_s* key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_IMPORT_WRAPPED_KEY
+       LOGD("security_keys_import_wrapped_key wrapped_key size = [" << wrapped_key.length << "]");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+       auto tz_key_type = to_tz_data_type(key_type);
+
+       TZSerializer s_in;
+       if (tz_algo_type == ALGO_RSA) {
+               s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                         tz_algo_type, tz_hash_type, tz_key_type,
+                                                         wrapped_key, key_pwd, key_id);
+       } else {
+               s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                         tz_algo_type, iv, ctr_len_or_tag_size_bits,
+                                                         aad, tz_key_type, wrapped_key, key_pwd, key_id);
+       }
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !key_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       CHECK_RET(execute(CMD_IMPORT_WRAPPED_KEY, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(key_tag);
+       }
+
+       LOGD("Imported object ID is (hex): " << raw_to_hex_string(key_id));
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+void get_data_size(const hal_security_keys_context_s context,
+                                  const hal_security_keys_data_s data_id,
+                                  const hal_security_keys_password_iv_tag_s pwd,
+                                  const tz_data_type type,
+                                  uint32_t &data_size)
+{
+       // command ID = CMD_GET_DATA_SIZE
+       LOGD("get_data_size");
+       LOGD("Object ID (passed to CMD_GET_DATA_SIZE) is (hex): " << raw_to_hex_string(data_id));
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data_id, pwd, type);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory);
+
+       execute(CMD_GET_DATA_SIZE, &op, *tz_session);
+       data_size = op.params[0].value.b;
+}
+
+int security_keys_export_wrapped_key(const hal_security_keys_context_s context,
+                                                                        const hal_security_keys_algo_type_e algo,
+                                                                        const hal_security_keys_hash_algorithm_e hash,
+                                                                        const hal_security_keys_data_s iv,
+                                                                        const hal_security_keys_data_s aad,
+                                                                        const size_t ctr_len_or_tag_size_bits,
+                                                                        const hal_security_keys_data_s wrapping_key_id,
+                                                                        const hal_security_keys_password_iv_tag_s wrapping_key_pwd,
+                                                                        const hal_security_keys_data_s key_id,
+                                                                        const hal_security_keys_password_iv_tag_s key_pwd,
+                                                                        const hal_security_keys_data_type_e key_type,
+                                                                        hal_security_keys_data_s* wrapped_key)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_EXPORT_WRAPPED_KEY
+       LOGD("security_keys_export_wrapped_key");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+       auto tz_key_type = to_tz_data_type(key_type);
+
+       TZSerializer s_in;
+       if (tz_algo_type == ALGO_RSA) {
+               s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                         tz_algo_type, tz_hash_type,
+                                                         key_id, key_pwd, tz_key_type);
+       } else {
+               s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                         tz_algo_type, iv, ctr_len_or_tag_size_bits,
+                                                         aad, key_id, key_pwd, tz_key_type);
+       }
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       uint32_t data_size = 0;
+       get_data_size(context, key_id, key_pwd, tz_key_type, data_size);
+       LOGD("get_data_size = [" << data_size << "]");
+
+       uint32_t enc_overhead = KM_ENCRYPTION_OVERHEAD;
+       if (tz_algo_type == ALGO_RSA)
+               enc_overhead = KM_RSA_BLOCK_SIZE;
+
+       // encrypted data may be longer
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(data_size + enc_overhead, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+       s_out.Serialize(out_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       CHECK_RET(execute(CMD_EXPORT_WRAPPED_KEY, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(wrapped_key);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_encapsulate_key(const hal_security_keys_context_s context,
+                                                                 const hal_security_keys_kem_type_e kem_type,
+                                                                 const hal_security_keys_data_s pub_key_id,
+                                                                 const hal_security_keys_password_iv_tag_s pub_key_pwd,
+                                                                 const hal_security_keys_data_s shared_secret_id,
+                                                                 const hal_security_keys_password_iv_s shared_secret_pwd,
+                                                                 hal_security_keys_data_s* ciphertext,
+                                                                 hal_security_keys_data_s* shared_secret_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_ENCAPSULATE_KEY
+       LOGD("security_keys_encapsulate_key");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_kem_type = to_tz_kem_type(kem_type);
+
+       TZSerializer s_in = makeSerializer(pub_key_id, pub_key_pwd,
+                                                                          shared_secret_pwd, shared_secret_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       uint32_t out_memory_size = 0;
+       switch (tz_kem_type) {
+               case ML_KEM_768:
+                       out_memory_size = 1088;
+                       break;
+               case ML_KEM_1024:
+                       out_memory_size = 1568;
+                       break;
+               default:
+                       return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+       }
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+
+       bool with_pwd = !shared_secret_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = tz_kem_type;
+
+       CHECK_RET(execute(CMD_ENCAPSULATE_KEY, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(ciphertext);
+       if (with_pwd)
+               s_out.Pull(shared_secret_tag);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_decapsulate_key(const hal_security_keys_context_s context,
+                                                                 const hal_security_keys_kem_type_e kem_type,
+                                                                 const hal_security_keys_data_s priv_key_id,
+                                                                 const hal_security_keys_password_iv_tag_s priv_key_pwd,
+                                                                 const hal_security_keys_data_s shared_secret_id,
+                                                                 const hal_security_keys_password_iv_s shared_secret_pwd,
+                                                                 const hal_security_keys_data_s ciphertext,
+                                                                 hal_security_keys_data_s* shared_secret_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DECAPSULATE_KEY
+       LOGD("security_keys_decapsulate_key");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_kem_type = to_tz_kem_type(kem_type);
+
+       TZSerializer s_in = makeSerializer(priv_key_id, priv_key_pwd,
+                                                                          shared_secret_pwd, shared_secret_id, ciphertext);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !shared_secret_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       op.params[0].value.a = tz_kem_type;
+
+       CHECK_RET(execute(CMD_DECAPSULATE_KEY, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(shared_secret_tag);
+       }
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_destroy_key(const hal_security_keys_context_s context,
+                                                         const hal_security_keys_data_s key_id)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DESTROY_KEY
+       LOGD("security_keys_destroy_key");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(key_id);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory);
+
+       return execute(CMD_DESTROY_KEY, &op, *tz_session);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_import_data(const hal_security_keys_context_s context,
+                                                         const hal_security_keys_data_s data_id,
+                                                         const hal_security_keys_password_iv_s data_pwd,
+                                                         const hal_security_keys_data_type_e data_type,
+                                                         const hal_security_keys_data_s data,
+                                                         const hal_security_keys_data_s data_encryption_iv,
+                                                         const hal_security_keys_data_s data_encryption_tag,
+                                                         hal_security_keys_data_s* data_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_IMPORT_DATA
+       LOGD("security_keys_import_data data size = [" << data.length << "]");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_data_type = to_tz_data_type(data_type);
+
+       uint32_t data_size_bits = data.length * 8;
+       auto s_in = makeSerializer(tz_data_type, data, data_size_bits, data_encryption_iv, data_encryption_tag,
+                                                          data_pwd, data_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !data_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       CHECK_RET(execute(CMD_IMPORT_DATA, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(data_tag);
+       }
+
+       LOGD("Imported object ID is (hex): " << raw_to_hex_string(data_id));
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_export_data(const hal_security_keys_context_s context,
+                                                         const hal_security_keys_data_s data_id,
+                                                         const hal_security_keys_password_iv_tag_s data_pwd,
+                                                         const hal_security_keys_data_type_e data_type,
+                                                         hal_security_keys_data_s* data)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GET_DATA
+       LOGD("security_keys_export_data");
+       LOGD("Object ID (passed to CMD_GET_DATA) is (hex): " << raw_to_hex_string(data_id));
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_data_type = to_tz_data_type(data_type);
+
+       auto s_in = makeSerializer(data_id, data_pwd, tz_data_type);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       uint32_t data_size = 0;
+       get_data_size(context, data_id, data_pwd, tz_data_type, data_size);
+       LOGD("get_data_size = [" << data_size << "]");
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(data_size));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+       s_out.Serialize(out_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+
+       CHECK_RET(execute(CMD_GET_DATA, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(data);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_wrap_concatenated_data(const hal_security_keys_context_s context,
+                                                                                const hal_security_keys_algo_type_e algo,
+                                                                                const hal_security_keys_hash_algorithm_e hash,
+                                                                                const hal_security_keys_data_s wrapping_key_id,
+                                                                                const hal_security_keys_password_iv_tag_s wrapping_key_pwd,
+                                                                                const hal_security_keys_data_s key_id,
+                                                                                const hal_security_keys_password_iv_tag_s key_pwd,
+                                                                                const hal_security_keys_data_s data,
+                                                                                hal_security_keys_data_s* wrapped_key)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_WRAP_CONCATENATED_DATA
+       LOGD("security_keys_wrap_concatenated_data");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+
+       if (tz_algo_type != ALGO_RSA) {
+               LOGE("Only RSA is supported in security_keys_wrap_concatenated_data");
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+       }
+
+       TZSerializer s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                                          tz_algo_type, tz_hash_type,
+                                                                          key_id, key_pwd, data);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       uint32_t out_memory_size = KM_RSA_BLOCK_SIZE;
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+       s_out.Serialize(out_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       CHECK_RET(execute(CMD_WRAP_CONCATENATED_DATA, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(wrapped_key);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_unwrap_concatenated_data(const hal_security_keys_context_s context,
+                                                                                  const hal_security_keys_algo_type_e algo,
+                                                                                  const hal_security_keys_hash_algorithm_e hash,
+                                                                                  const hal_security_keys_data_s wrapping_key_id,
+                                                                                  const hal_security_keys_password_iv_tag_s wrapping_key_pwd,
+                                                                                  const hal_security_keys_data_s wrapped_key,
+                                                                                  const hal_security_keys_data_s key_id,
+                                                                                  const hal_security_keys_password_iv_s key_pwd,
+                                                                                  const hal_security_keys_data_type_e key_type,
+                                                                                  const size_t key_size_bits,
+                                                                                  hal_security_keys_data_s* data,
+                                                                                  hal_security_keys_data_s* key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_UNWRAP_CONCATENATED_DATA
+       LOGD("security_keys_unwrap_concatenated_data");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+       auto tz_key_type = to_tz_data_type(key_type);
+
+       if (tz_algo_type != ALGO_RSA) {
+               LOGE("Only RSA is supported in security_keys_unwrap_concatenated_data");
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+       }
+
+       TZSerializer s_in = makeSerializer(wrapping_key_id, wrapping_key_pwd,
+                                                                          tz_algo_type, tz_hash_type, tz_key_type,
+                                                                          wrapped_key, key_pwd, key_id, key_size_bits);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       uint32_t out_memory_size = KM_RSA_BLOCK_SIZE;
+       bool with_pwd = !key_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               out_memory_size += Params::DEFAULT_AES_GCM_TAG_LEN_BYTES;
+
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+       s_out.Serialize(out_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       CHECK_RET(execute(CMD_UNWRAP_CONCATENATED_DATA, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(data);
+       if (with_pwd)
+               s_out.Pull(key_tag);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_encrypt_data_auth(const hal_security_keys_context_s context,
+                                                                       const hal_security_keys_data_s key_id,
+                                                                       const hal_security_keys_password_iv_tag_s key_pwd,
+                                                                       const hal_security_keys_data_s data,
+                                                                       const hal_security_keys_data_s iv,
+                                                                       const hal_security_keys_data_s aad,
+                                                                       const size_t tag_size_bits,
+                                                                       hal_security_keys_data_s* tag,
+                                                                       hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_ENCRYPT
+       LOGD("security_keys_encrypt_data_auth");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data, key_pwd, iv, key_id, aad, tag_size_bits);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       uint32_t out_memory_size = static_cast<uint32_t>(data.length + Params::CIPHER_EXTRA_PADDING_SIZE);
+       uint32_t tag_size_bytes = (tag_size_bits + 7) / 8;
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+       s_out.Push(new TZSerializableBinary(tag_size_bytes));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = ALGO_AES_GCM;
+
+       CHECK_RET(execute(CMD_ENCRYPT, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+       s_out.Pull(tag);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_decrypt_data_auth(const hal_security_keys_context_s context,
+                                                                       const hal_security_keys_data_s key_id,
+                                                                       const hal_security_keys_password_iv_tag_s key_pwd,
+                                                                       const hal_security_keys_data_s data,
+                                                                       const hal_security_keys_data_s iv,
+                                                                       const hal_security_keys_data_s aad,
+                                                                       const size_t tag_size_bits,
+                                                                       const hal_security_keys_data_s tag,
+                                                                       hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DECRYPT
+       LOGD("security_keys_decrypt_data_auth");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data, key_pwd, iv, key_id, aad, tag_size_bits, tag);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(data.length));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = ALGO_AES_GCM;
+
+       CHECK_RET(execute(CMD_DECRYPT, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_encrypt_data(const hal_security_keys_context_s context,
+                                                          const hal_security_keys_algo_type_e algo,
+                                                          const hal_security_keys_hash_algorithm_e hash,
+                                                          const hal_security_keys_data_s key_id,
+                                                          const hal_security_keys_password_iv_tag_s key_pwd,
+                                                          const hal_security_keys_data_s data,
+                                                          const hal_security_keys_data_s iv,
+                                                          hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_ENCRYPT
+       LOGD("security_keys_encrypt_data");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer (size = " <<
+                       std::to_string(key_id.length) << ")");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+
+       TZSerializer s_in;
+       if (tz_algo_type == ALGO_RSA)
+               s_in = makeSerializer(data, key_pwd, tz_hash_type, key_id);
+       else
+               s_in = makeSerializer(data, key_pwd, iv, key_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       uint32_t out_memory_size;
+       if (tz_algo_type == ALGO_RSA)
+               out_memory_size = get_tz_max_key_size(ALGO_RSA);
+       else
+               out_memory_size = static_cast<uint32_t>(data.length + Params::CIPHER_EXTRA_PADDING_SIZE);
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = tz_algo_type;
+
+       CHECK_RET(execute(CMD_ENCRYPT, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_decrypt_data(const hal_security_keys_context_s context,
+                                                          const hal_security_keys_algo_type_e algo,
+                                                          const hal_security_keys_hash_algorithm_e hash,
+                                                          const hal_security_keys_data_s key_id,
+                                                          const hal_security_keys_password_iv_tag_s key_pwd,
+                                                          const hal_security_keys_data_s data,
+                                                          const hal_security_keys_data_s iv,
+                                                          hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DECRYPT
+       LOGD("security_keys_decrypt_data");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer (size = " <<
+                       std::to_string(key_id.length) << ")");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+
+       TZSerializer s_in;
+       if (tz_algo_type == ALGO_RSA)
+               s_in = makeSerializer(data, key_pwd, tz_hash_type, key_id);
+       else
+               s_in = makeSerializer(data, key_pwd, iv, key_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       // decrypt operation does not require padding
+       uint32_t out_memory_size = data.length;
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(out_memory_size, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = tz_algo_type;
+
+       CHECK_RET(execute(CMD_DECRYPT, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_destroy_data(const hal_security_keys_context_s context,
+                                                          const hal_security_keys_data_s data_id)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DESTROY_DATA
+       LOGD("security_keys_destroy_data");
+       LOGD("Object ID (passed to CMD_DESTROY_DATA) is (hex): " << raw_to_hex_string(data_id));
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data_id);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_OUTPUT, in_memory);
+
+       return execute(CMD_DESTROY_DATA, &op, *tz_session);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_cipher_initialize(const hal_security_keys_context_s context,
+                                                                       const bool encrypt,
+                                                                       const hal_security_keys_data_s key_id,
+                                                                       const hal_security_keys_password_iv_tag_s key_pwd,
+                                                                       const hal_security_keys_data_s iv,
+                                                                       const hal_security_keys_data_s aad,
+                                                                       const size_t tag_size_bits,
+                                                                       hal_security_keys_cipher_context_t* cipher_context)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_CIPHER_INIT
+       LOGD("security_keys_cipher_initialize");
+
+       if (key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(key_pwd, iv, key_id, aad, tag_size_bits);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       op.params[0].value.a = ALGO_AES_GCM;
+       op.params[0].value.b = encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT;
+
+       CHECK_RET(execute(CMD_CIPHER_INIT, &op, *tz_session));
+
+       *cipher_context = op.params[0].value.b;
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_cipher_add_aad(const hal_security_keys_context_s context,
+                                                                const hal_security_keys_cipher_context_t cipher_context,
+                                                                const hal_security_keys_data_s aad)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_CIPHER_INIT_AAD
+       LOGD("security_keys_cipher_add_aad");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(aad);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       op.params[0].value.a = cipher_context;
+
+       return execute(CMD_CIPHER_INIT_AAD, &op, *tz_session);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_cipher_update(const hal_security_keys_context_s context,
+                                                               const hal_security_keys_cipher_context_t cipher_context,
+                                                               const hal_security_keys_data_s data,
+                                                               hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_CIPHER_UPDATE
+       LOGD("security_keys_cipher_update");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(data.length));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = cipher_context;
+
+       CHECK_RET(execute(CMD_CIPHER_UPDATE, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_cipher_finalize(const hal_security_keys_context_s context,
+                                                                 const hal_security_keys_cipher_context_t cipher_context,
+                                                                 const hal_security_keys_data_s data,
+                                                                 hal_security_keys_data_s* out)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_CIPHER_FINALIZE
+       LOGD("security_keys_cipher_finalize");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto s_in = makeSerializer(data);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = cipher_context;
+
+       CHECK_RET(execute(CMD_CIPHER_FINALIZE, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(out);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_cipher_free(const hal_security_keys_context_s context,
+                                                         const hal_security_keys_cipher_context_t cipher_context)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_CIPHER_CLEANUP
+       LOGD("security_keys_cipher_free");
+
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       TEEC_Operation op;
+       op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
+       op.params[0].value.a = cipher_context;
+
+       return execute(CMD_CIPHER_CLEANUP, &op, *tz_session);
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_create_signature(const hal_security_keys_context_s context,
+                                                                  const hal_security_keys_algo_type_e algo,
+                                                                  const hal_security_keys_hash_algorithm_e hash,
+                                                                  const hal_security_keys_data_s priv_key_id,
+                                                                  const hal_security_keys_password_iv_tag_s priv_key_pwd,
+                                                                  const hal_security_keys_data_s message,
+                                                                  hal_security_keys_data_s* signature)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_SIGN
+       LOGD("security_keys_create_signature");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+       auto tz_max_key_size = get_tz_max_key_size(tz_algo_type);
+
+       if (priv_key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer (size = " <<
+                       std::to_string(priv_key_id.length) << ")");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       auto s_in = makeSerializer(message, priv_key_pwd, priv_key_id);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       s_out.Push(new TZSerializableBinary(tz_max_key_size, false));
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = tz_algo_type;
+       op.params[0].value.b = tz_hash_type;
+
+       CHECK_RET(execute(CMD_SIGN, &op, *tz_session));
+
+       s_out.Deserialize(out_memory);
+       s_out.Pull(signature);
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_verify_signature(const hal_security_keys_context_s context,
+                                                                  const hal_security_keys_algo_type_e algo,
+                                                                  const hal_security_keys_hash_algorithm_e hash,
+                                                                  const hal_security_keys_data_s pub_key_id,
+                                                                  const hal_security_keys_password_iv_tag_s pub_key_pwd,
+                                                                  const hal_security_keys_data_s message,
+                                                                  const hal_security_keys_data_s signature)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_VERIFY
+       LOGD("security_keys_verify_signature");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_algo_type = to_tz_algo_type(algo);
+       auto tz_hash_type = to_tz_hash_type(hash);
+
+       if (pub_key_id.length != KM_KEY_ID_SIZE) {
+               LOGE("TZ Backend received incorrect key buffer (size = " <<
+                       std::to_string(pub_key_id.length) << ")");
+               return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       auto s_in = makeSerializer(message, signature, pub_key_pwd, pub_key_id);
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       op.params[0].value.a = tz_algo_type;
+       op.params[0].value.b = tz_hash_type;
+
+       CHECK_RET(execute(CMD_VERIFY, &op, *tz_session));
+
+       int ret = op.params[0].value.a;
+       switch (ret) {
+               case KM_TA_SUCCESS:
+                       return HAL_SECURITY_KEYS_ERROR_NONE;
+               case KM_TA_ERROR_SIGNATURE:
+                       LOGW("Signature verification failed");
+                       return HAL_SECURITY_KEYS_ERROR_VERIFICATION_FAILED;
+               default:
+                       LOGE("Unknown TA error during operation: " << ret);
+                       return HAL_SECURITY_KEYS_ERROR_INTERNAL_ERROR;
+       }
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_derive_ecdh(const hal_security_keys_context_s context,
+                                                         const hal_security_keys_ec_type_e ec_type,
+                                                         const hal_security_keys_data_s pub_key_x,
+                                                         const hal_security_keys_data_s pub_key_y,
+                                                         const hal_security_keys_data_s priv_key_id,
+                                                         const hal_security_keys_password_iv_tag_s priv_key_pwd,
+                                                         const hal_security_keys_data_s secret_id,
+                                                         const hal_security_keys_password_iv_s secret_pwd,
+                                                         hal_security_keys_data_s* secret_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DERIVE
+       LOGD("security_keys_derive_ecdh");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_ec_type = to_tz_ec_type(ec_type);
+
+       auto s_in = makeSerializer(priv_key_id, priv_key_pwd, tz_ec_type,
+                                                          pub_key_x, pub_key_y, secret_pwd, secret_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !secret_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = ALGO_ECDH_DRV;
+
+       CHECK_RET(execute(CMD_DERIVE, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(secret_tag);
+       }
+
+       LOGD("Derived object ID is (hex): " << raw_to_hex_string(secret_id));
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_derive_kbkdf(const hal_security_keys_context_s context,
+                                                          const hal_security_keys_kbkdf_params_s params,
+                                                          const hal_security_keys_data_s secret_id,
+                                                          const hal_security_keys_password_iv_tag_s secret_pwd,
+                                                          const hal_security_keys_data_s key_id,
+                                                          const hal_security_keys_password_iv_s key_pwd,
+                                                          hal_security_keys_data_s* key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DERIVE
+       LOGD("security_keys_derive_kbkdf");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_prf = to_tz_prf(params.prf);
+       auto tz_mode = to_tz_kbkdf_mode(params.mode);
+       auto tz_location = to_tz_kbkdf_ctr_loc(params.location);
+
+       auto s_in = makeSerializer(secret_id, secret_pwd,
+                                                          params.length, params.label, params.context, params.fixed,
+                                                          tz_prf, tz_mode, tz_location,
+                                                          params.rlen, params.llen, params.no_separator,
+                                                          key_pwd, key_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !key_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = ALGO_KBKDF_DRV;
+
+       CHECK_RET(execute(CMD_DERIVE, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(key_tag);
+       }
+
+       LOGD("Derived object ID is (hex): " << raw_to_hex_string(key_id));
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_derive_hybrid_kbkdf(const hal_security_keys_context_s context,
+                                                                         const hal_security_keys_kbkdf_params_s params,
+                                                                         const hal_security_keys_data_s first_secret_id,
+                                                                         const hal_security_keys_password_iv_tag_s first_secret_pwd,
+                                                                         const hal_security_keys_data_s second_secret_id,
+                                                                         const hal_security_keys_password_iv_tag_s second_secret_pwd,
+                                                                         const hal_security_keys_data_s key_id,
+                                                                         const hal_security_keys_password_iv_s key_pwd,
+                                                                         hal_security_keys_data_s* key_tag)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_DERIVE_HYBRID
+       LOGD("security_keys_derive_hybrid_kbkdf");
+
+       TEEC_Context* tz_context = static_cast<TEEC_Context*>(context.ctx);
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       auto tz_prf = to_tz_prf(params.prf);
+       auto tz_mode = to_tz_kbkdf_mode(params.mode);
+       auto tz_location = to_tz_kbkdf_ctr_loc(params.location);
+
+       auto s_in = makeSerializer(first_secret_id, first_secret_pwd,
+                                                          second_secret_id, second_secret_pwd,
+                                                          params.length, params.label, params.context, params.fixed,
+                                                          tz_prf, tz_mode, tz_location,
+                                                          params.rlen, params.llen, params.no_separator,
+                                                          key_pwd, key_id);
+
+       TrustZoneMemory in_memory(*tz_context, s_in.GetSize(), TEEC_MEM_INPUT);
+       s_in.Serialize(in_memory);
+
+       TZSerializer s_out;
+       bool with_pwd = !key_pwd.password.buffer ? 0 : 1;
+       if (with_pwd)
+               s_out.Push(new TZSerializableBinary(Params::DEFAULT_AES_GCM_TAG_LEN_BYTES));
+
+       TrustZoneMemory out_memory(*tz_context, s_out.GetSize(), TEEC_MEM_OUTPUT);
+
+       TEEC_Operation op = make_op(TEEC_VALUE_INOUT, in_memory);
+       if (with_pwd)
+               op = make_op(TEEC_VALUE_INOUT, in_memory, out_memory);
+       op.params[0].value.a = ALGO_KBKDF_DRV;
+
+       CHECK_RET(execute(CMD_DERIVE_HYBRID, &op, *tz_session));
+
+       if (with_pwd) {
+               s_out.Deserialize(out_memory);
+               s_out.Pull(key_tag);
+       }
+
+       LOGD("Derived object ID is (hex): " << raw_to_hex_string(key_id));
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+int security_keys_get_max_chunk_size(const hal_security_keys_context_s context,
+                                                                        size_t* chunk_size)
+{
+       EXCEPTION_GUARD_START
+
+       // command ID = CMD_GET_MAX_CHUNK_SIZE
+       LOGD("security_keys_get_max_chunk_size");
+
+       TEEC_Session* tz_session = static_cast<TEEC_Session*>(context.session);
+
+       TEEC_Operation op;
+       op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+       CHECK_RET(execute(CMD_GET_MAX_CHUNK_SIZE, &op, *tz_session));
+
+       *chunk_size = op.params[0].value.b;
+
+       return 0;
+
+       EXCEPTION_GUARD_END
+}
+
+static int security_keys_backend_init(void **data)
+{
+       hal_backend_security_keys_funcs *security_keys_funcs;
+
+       if (!data)
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+
+       security_keys_funcs = *(hal_backend_security_keys_funcs **)data;
+       if (!security_keys_funcs)
+               return HAL_SECURITY_KEYS_ERROR_INVALID_PARAMETER;
+
+       security_keys_funcs->context_initialize = security_keys_context_initialize;
+       security_keys_funcs->context_free = security_keys_context_free;
+       security_keys_funcs->create_iv = security_keys_create_iv;
+       security_keys_funcs->create_key_aes = security_keys_create_key_aes;
+       security_keys_funcs->create_key_pair_rsa = security_keys_create_key_pair_rsa;
+       security_keys_funcs->create_key_pair_dsa = security_keys_create_key_pair_dsa;
+       security_keys_funcs->create_key_pair_ecdsa = security_keys_create_key_pair_ecdsa;
+       security_keys_funcs->create_key_pair_kem = security_keys_create_key_pair_kem;
+       security_keys_funcs->import_wrapped_key = security_keys_import_wrapped_key;
+       security_keys_funcs->export_wrapped_key = security_keys_export_wrapped_key;
+       security_keys_funcs->encapsulate_key = security_keys_encapsulate_key;
+       security_keys_funcs->decapsulate_key = security_keys_decapsulate_key;
+       security_keys_funcs->destroy_key = security_keys_destroy_key;
+       security_keys_funcs->import_data = security_keys_import_data;
+       security_keys_funcs->export_data = security_keys_export_data;
+       security_keys_funcs->wrap_concatenated_data = security_keys_wrap_concatenated_data;
+       security_keys_funcs->unwrap_concatenated_data = security_keys_unwrap_concatenated_data;
+       security_keys_funcs->encrypt_data_auth = security_keys_encrypt_data_auth;
+       security_keys_funcs->decrypt_data_auth = security_keys_decrypt_data_auth;
+       security_keys_funcs->encrypt_data = security_keys_encrypt_data;
+       security_keys_funcs->decrypt_data = security_keys_decrypt_data;
+       security_keys_funcs->destroy_data = security_keys_destroy_data;
+       security_keys_funcs->cipher_initialize = security_keys_cipher_initialize;
+       security_keys_funcs->cipher_add_aad = security_keys_cipher_add_aad;
+       security_keys_funcs->cipher_update = security_keys_cipher_update;
+       security_keys_funcs->cipher_finalize = security_keys_cipher_finalize;
+       security_keys_funcs->cipher_free = security_keys_cipher_free;
+       security_keys_funcs->create_signature = security_keys_create_signature;
+       security_keys_funcs->verify_signature = security_keys_verify_signature;
+       security_keys_funcs->derive_ecdh = security_keys_derive_ecdh;
+       security_keys_funcs->derive_kbkdf = security_keys_derive_kbkdf;
+       security_keys_funcs->derive_hybrid_kbkdf = security_keys_derive_hybrid_kbkdf;
+       security_keys_funcs->get_max_chunk_size = security_keys_get_max_chunk_size;
+
+       return 0;
+}
+
+static int security_keys_backend_exit(void *data)
+{
+       (void) data;
+       return 0;
+}
+
+EXPORT hal_backend hal_backend_security_keys_data = {
+       .name = "backend_security_keys",
+       .vendor = "Samsung",
+       .init = security_keys_backend_init,
+       .exit = security_keys_backend_exit,
+       .major_version = 1,
+       .minor_version = 0,
+};
diff --git a/src/log.cpp b/src/log.cpp
new file mode 100644 (file)
index 0000000..a57307d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#include <syslog.h>
+#include <dlog.h>
+
+#ifdef NDEBUG
+int __log_level = LOG_ERR;
+#else
+int __log_level = LOG_DEBUG;
+#endif
+
+#define SECURITY_KEYS_LOG_TAG "SECURITY_KEYS_BACKEND"
+
+void security_keys_print(int priority, char const *fmt, ...)
+{
+       log_priority dlog_prio;
+
+       switch (priority) {
+               case LOG_EMERG:
+                       dlog_prio = DLOG_FATAL;
+                       break;
+               case LOG_ERR:
+                       dlog_prio = DLOG_ERROR;
+                       break;
+               case LOG_WARNING:
+                       dlog_prio = DLOG_WARN;
+                       break;
+               case LOG_INFO:
+                       dlog_prio = DLOG_INFO;
+                       break;
+               case LOG_DEBUG:
+                       dlog_prio = DLOG_DEBUG;
+                       break;
+               default:
+                       dlog_prio = DLOG_DEFAULT;
+       }
+
+       va_list ap;
+       va_start(ap, fmt);
+       (void) dlog_vprint(dlog_prio, SECURITY_KEYS_LOG_TAG, fmt, ap);
+       va_end(ap);
+}
diff --git a/src/log.h b/src/log.h
new file mode 100644 (file)
index 0000000..a3a35f0
--- /dev/null
+++ b/src/log.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <stdlib.h>
+#include <syslog.h>
+
+#define UNUSED __attribute__((unused))
+
+extern int __log_level;
+extern void security_keys_print(int priority, char const *fmt, ...);
+
+namespace {
+       template <typename ...Args>
+       void UNUSED __LOG_FUN(int level, const std::stringstream &format, Args&&... args) {
+               security_keys_print(level, format.str().c_str(), std::forward<Args>(args)...);
+       }
+
+       template <>
+       void UNUSED __LOG_FUN(int level, const std::stringstream &format) {
+               security_keys_print(level, "%s", format.str().c_str());
+       }
+
+       template <typename ...Args>
+       void UNUSED __LOG_FUN(int level, const char *format, Args&&... args) {
+               security_keys_print(level, format, std::forward<Args>(args)...);
+       }
+
+       template <>
+       void UNUSED __LOG_FUN(int level, const char *format) {
+               security_keys_print(level, "%s", format);
+       }
+
+} // namespace anonymous
+
+#define __FILENAME__ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define __LOG(LEVEL, FORMAT, ...) \
+       do { \
+               if (LEVEL <= __log_level) { \
+                       std::stringstream __LOG_FORMAT; \
+                       __LOG_FORMAT << __FILENAME__ << ": " << __func__ << "(" << __LINE__ << ") > " << FORMAT; \
+                       __LOG_FUN(LEVEL, __LOG_FORMAT, ##__VA_ARGS__); \
+               } \
+       } while (0)
+
+#define LOGM(...)  __LOG(LOG_EMERG, __VA_ARGS__)   /* system is unusable */
+#define LOGE(...)  __LOG(LOG_ERR, __VA_ARGS__)     /* error conditions */
+#define LOGW(...)  __LOG(LOG_WARNING, __VA_ARGS__) /* warning conditions */
+#define LOGI(...)  __LOG(LOG_INFO, __VA_ARGS__)    /* informational */
+#define LOGD(...)  __LOG(LOG_DEBUG, __VA_ARGS__)   /* debug-level messages */
diff --git a/src/tz-memory.cpp b/src/tz-memory.cpp
new file mode 100644 (file)
index 0000000..76007cc
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#include <cstring>
+#include <stdexcept>
+
+#include "log.h"
+#include "tz-memory.h"
+
+TrustZoneMemory::TrustZoneMemory(TEEC_Context &context, const size_t size, const uint32_t flags)
+{
+       Allocate(context, size, flags);
+}
+
+TrustZoneMemory::~TrustZoneMemory()
+{
+       Release();
+}
+
+void TrustZoneMemory::Allocate(TEEC_Context &context, const size_t size, const uint32_t flags)
+{
+       LOGD("Allocating " << size << " bytes of shared TZ memory, flags: " << flags);
+
+       m_SharedMemory.size = size;
+       m_SharedMemory.flags = flags;
+
+       if (size != 0) {
+               TEEC_Result result = TEEC_AllocateSharedMemory(&context, &m_SharedMemory);
+               if (result != TEEC_SUCCESS)
+                       throw std::bad_alloc();
+
+               memset(m_SharedMemory.buffer, 0, m_SharedMemory.size);
+       } else {
+               m_SharedMemory.buffer = NULL;
+               m_SharedMemory.size = 0;
+       }
+}
+
+TEEC_SharedMemory* TrustZoneMemory::Get() const
+{
+       return &m_SharedMemory;
+}
+
+void TrustZoneMemory::Release()
+{
+       if (m_SharedMemory.size != 0)
+               TEEC_ReleaseSharedMemory(&m_SharedMemory);
+}
diff --git a/src/tz-memory.h b/src/tz-memory.h
new file mode 100644 (file)
index 0000000..8771907
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <tee_client_api.h>
+
+class TrustZoneMemory final
+{
+public:
+       TrustZoneMemory(TEEC_Context &context, const size_t size, const uint32_t flags);
+       TrustZoneMemory(const TrustZoneMemory&) = delete;
+       TrustZoneMemory(TrustZoneMemory &&) = delete;
+       TrustZoneMemory& operator=(const TrustZoneMemory&) = delete;
+       TrustZoneMemory& operator=(TrustZoneMemory &&) = delete;
+       ~TrustZoneMemory();
+
+       TEEC_SharedMemory* Get() const;
+
+private:
+       void Allocate(TEEC_Context &context, const size_t size, const uint32_t flags);
+       void Release();
+
+       mutable TEEC_SharedMemory m_SharedMemory;
+};
diff --git a/src/tz-serializer.cpp b/src/tz-serializer.cpp
new file mode 100644 (file)
index 0000000..6193f70
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#include <stdexcept>
+#include <string.h>
+
+#include "crypto-params.h"
+#include "tz-serializer.h"
+
+// TZSerializable
+void TZSerializable::Pull(hal_security_keys_data_s*) const
+{
+       throw std::runtime_error("This serializable does not support conversion to hal_security_keys_data_s");
+}
+
+void TZSerializable::Pull(uint32_t &) const
+{
+       throw std::runtime_error("This serializable does not support conversion to uint32_t");
+}
+
+// TZSerializableBinary
+TZSerializableBinary::TZSerializableBinary(uint32_t data_size, bool is_size_fixed)
+{
+       m_data.data = nullptr;
+       m_data.data_size = data_size;
+       m_isSizeFixed = is_size_fixed;
+       m_expectedSize = data_size;
+}
+
+TZSerializableBinary::TZSerializableBinary(const hal_security_keys_data_s &data)
+{
+       m_data.data = !data.buffer ? nullptr : data.buffer;
+       m_data.data_size = data.length;
+       m_isSizeFixed = true;
+       m_expectedSize = data.length;
+}
+
+uint32_t TZSerializableBinary::GetSize() const
+{
+       return KM_SizeOfBinaryData(const_cast<KM_BinaryData*>(&m_data));
+}
+
+int TZSerializableBinary::Serialize(void **buffer, uint32_t *size_guard) const
+{
+       return KM_SerializeBinaryData(buffer, size_guard, const_cast<KM_BinaryData*>(&m_data));
+}
+
+int TZSerializableBinary::Deserialize(void **buffer, uint32_t *size_guard)
+{
+       int ret = KM_DeserializeBinaryData(buffer, size_guard, &m_data);
+       if (m_isSizeFixed) {
+               if (m_data.data_size != m_expectedSize)
+                       throw std::runtime_error("Size of deserialized data differ from size given in constructor.");
+       } else {
+               if (m_data.data_size > m_expectedSize)
+                       throw std::runtime_error("Size of deserialized data is bigger than size given in constructor.");
+       }
+       return ret;
+}
+
+void TZSerializableBinary::Pull(hal_security_keys_data_s* buf) const
+{
+       buf->buffer = (unsigned char*)malloc(m_data.data_size);
+       if (!(buf->buffer))
+               throw std::bad_alloc();
+
+       buf->length =  m_data.data_size;
+       memcpy(buf->buffer, m_data.data, m_data.data_size);
+}
+
+// TZSerializablePwdData
+TZSerializablePwdData::TZSerializablePwdData(const hal_security_keys_data_s &pwd,
+                                                                                        const hal_security_keys_data_s &iv,
+                                                                                        uint32_t tagSizeBits,
+                                                                                        const hal_security_keys_data_s &tag)
+{
+       memset(&m_data, 0, sizeof(KM_PwdData));
+       m_data.pwd = !pwd.buffer ? nullptr : pwd.buffer;
+       m_data.pwd_size = pwd.length;
+       m_data.iv = !iv.buffer ? nullptr : iv.buffer;
+       m_data.iv_size = iv.length;
+       m_data.tag = !tag.buffer ? nullptr : tag.buffer;
+       m_data.tag_size = tag.length;
+       m_data.derive_len_bits = Params::DERIVED_KEY_LENGTH_BITS;
+       m_data.it_count = Params::DERIVED_KEY_ITERATIONS;
+       m_data.tag_len_bits = tagSizeBits;
+}
+
+uint32_t TZSerializablePwdData::GetSize() const
+{
+       return KM_SizeOfPwdData(const_cast<KM_PwdData*>(&m_data));
+}
+
+int TZSerializablePwdData::Serialize(void **buffer, uint32_t *size_guard) const
+{
+       return KM_SerializePwdData(buffer, size_guard, const_cast<KM_PwdData*>(&m_data));
+}
+
+int TZSerializablePwdData::Deserialize(void **, uint32_t *)
+{
+       throw std::runtime_error("Should not receive any password data from the TA");
+}
+
+// TZSerializableFlag
+uint32_t TZSerializableFlag::GetSize() const
+{
+       return KM_SizeOfFlag();
+}
+
+int TZSerializableFlag::Serialize(void **buffer, uint32_t *size_guard) const
+{
+       return KM_SerializeFlag(buffer, size_guard, m_flag);
+}
+
+int TZSerializableFlag::Deserialize(void **buffer, uint32_t *size_guard)
+{
+       return KM_DeserializeFlag(buffer, size_guard, &m_flag);
+}
+
+void TZSerializableFlag::Pull(uint32_t &flag) const
+{
+       flag = m_flag;
+}
+
+// TZSerializer
+void TZSerializer::Push(TZSerializable *serializable)
+{
+       m_serializables.emplace_back(serializable);
+       m_memorySize += serializable->GetSize();
+}
+
+void TZSerializer::Serialize(TrustZoneMemory &memory) const
+{
+       void *inBuffer = memory.Get()->buffer;
+       uint32_t inBufferGuard = m_memorySize;
+
+       for (const auto& s : m_serializables) {
+               int ret = s->Serialize(&inBuffer, &inBufferGuard);
+               if (ret)
+                       throw std::runtime_error("Failed to serialize data, ret: " + ret);
+       }
+}
+
+void TZSerializer::Deserialize(const TrustZoneMemory &memory)
+{
+       void *outBuffer = memory.Get()->buffer;
+       uint32_t outBufferGuard = m_memorySize;
+
+       for (const auto& s : m_serializables) {
+               int ret = s->Deserialize(&outBuffer, &outBufferGuard);
+               if (ret)
+                       throw std::runtime_error("Failed to deserialize data, ret: " + ret);
+       }
+}
diff --git a/src/tz-serializer.h b/src/tz-serializer.h
new file mode 100644 (file)
index 0000000..bff9588
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <list>
+#include <memory>
+#include <stdexcept>
+
+#include <hal/hal-security-keys-types.h>
+#include <km_serialization.h>
+
+#include "tz-memory.h"
+
+class TZSerializable {
+public:
+       TZSerializable() {}
+       virtual ~TZSerializable() {}
+       TZSerializable(const TZSerializable&) = delete;
+       TZSerializable& operator=(const TZSerializable&) = delete;
+
+       virtual uint32_t GetSize() const = 0;
+       virtual int Serialize(void **buffer, uint32_t *size_guard) const = 0;
+       virtual int Deserialize(void **buffer, uint32_t *size_guard) = 0;
+       virtual void Pull(hal_security_keys_data_s* buffer) const;
+       virtual void Pull(uint32_t &flag) const;
+};
+
+class TZSerializableBinary : public TZSerializable {
+public:
+       explicit TZSerializableBinary(uint32_t data_size, bool is_size_fixed = true);
+       explicit TZSerializableBinary(const hal_security_keys_data_s &data);
+       uint32_t GetSize() const override;
+       int Serialize(void **buffer, uint32_t *size_guard) const override;
+       int Deserialize(void **buffer, uint32_t *size_guard) override;
+       void Pull(hal_security_keys_data_s* buffer) const override;
+private:
+       KM_BinaryData m_data;
+       bool m_isSizeFixed;
+       uint32_t m_expectedSize;
+};
+
+class TZSerializablePwdData : public TZSerializable {
+public:
+       TZSerializablePwdData(const hal_security_keys_data_s &pwd,
+                                                 const hal_security_keys_data_s &iv,
+                                                 uint32_t tagSizeBits,
+                                                 const hal_security_keys_data_s &tag = {nullptr, 0});
+       uint32_t GetSize() const override;
+       int Serialize(void **buffer, uint32_t *size_guard) const override;
+       int Deserialize(void **buffer, uint32_t *size_guard) override;
+private:
+       KM_PwdData m_data;
+};
+
+class TZSerializableFlag : public TZSerializable {
+public:
+       TZSerializableFlag() : m_flag(0) {}
+       explicit TZSerializableFlag(uint32_t flag) : m_flag(flag) {}
+       uint32_t GetSize() const override;
+       int Serialize(void **buffer, uint32_t *size_guard) const override;
+       int Deserialize(void **buffer, uint32_t *size_guard) override;
+       void Pull(uint32_t &flag) const override;
+private:
+       uint32_t m_flag;
+};
+
+class TZSerializer {
+public:
+       TZSerializer() : m_memorySize(0) {}
+       ~TZSerializer() {}
+       TZSerializer(const TZSerializer&) = delete;
+       TZSerializer(TZSerializer&&) = default;
+       TZSerializer& operator=(const TZSerializer&) = delete;
+       TZSerializer& operator=(TZSerializer&&) = default;
+
+       void Push(TZSerializable *serializable);
+
+       template <typename T>
+       void Pull(T &buffer);
+       uint32_t GetSize() const { return m_memorySize; }
+       void Serialize(TrustZoneMemory &memory) const;
+       void Deserialize(const TrustZoneMemory &memory);
+
+private:
+       std::list<std::unique_ptr<TZSerializable>> m_serializables;
+       uint32_t m_memorySize;
+};
+
+template <typename T>
+void TZSerializer::Pull(T &data)
+{
+       if (m_serializables.empty()) {
+               throw std::runtime_error("No more serializables to extract");
+       }
+
+       m_serializables.front()->Pull(data);
+       m_serializables.pop_front();
+}