Check KBKDF parameters on key-manager side
[platform/core/security/key-manager.git] / src / manager / crypto / tz-backend / internals.cpp
index bfb78d7..2a5d83c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2017-2020 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.
 #include <generic-backend/algo-validation.h>
 #include <generic-backend/crypto-params.h>
 #include <dpl/log/log.h>
+#include <utils.h>
+#include <openssl/evp.h>
+#include <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
 
 #include <tz-backend/internals.h>
 #include <tz-backend/tz-context.h>
+#include <openssl-error-handler.h>
 #include <km_ta_defines.h>
+#include <key-impl.h>
 
+#include <functional>
+
+#ifndef __has_cpp_attribute
+#define __has_cpp_attribute(_) 0
+#endif
+
+#if __has_cpp_attribute(fallthrough)
+#define fallthru [[fallthrough]]
+#else
+#define fallthru ((void)0)
+#endif
+
+namespace {
+
+CKM::RawBuffer extractBignumData(const BIGNUM* bn)
+{
+       size_t size = static_cast<size_t>(BN_num_bytes(bn));
+
+       CKM::RawBuffer result(size);
+       int ret = BN_bn2bin(bn, result.data());
+       if (ret != static_cast<int>(size)) {
+               ThrowErr(CKM::Exc::Crypto::InternalError,
+                       "Error while converting bignums - expected "
+                       + std::to_string(size) + " bytes of data, got " + std::to_string(ret));
+       }
+
+       return result;
+}
+
+void generateDSAParams(const int sizeBits, CKM::RawBuffer &prime,
+                                       CKM::RawBuffer &subprime, CKM::RawBuffer &base)
+{
+       auto dsa = uptr<DSA_free>(DSA_new());
+       if (!dsa) {
+               ThrowErr(CKM::Exc::Crypto::InternalError,
+                       "Failed to create DSA context for parameter gen");
+       }
+
+       if (DSA_generate_parameters_ex(dsa.get(), sizeBits, NULL, 0, NULL, NULL, NULL) == 0) {
+               ThrowErr(CKM::Exc::Crypto::InternalError,
+                       "Failed to generate DSA params, err = " + std::to_string(ERR_get_error()));
+       }
+
+       // at this stage dsa->p, dsa->q & dsa->r should contain our params
+       // extract them into buffers
+       const BIGNUM *p, *q, *g;
+       DSA_get0_pqg(dsa.get(), &p, &q, &g);
+       prime = extractBignumData(p);
+       subprime = extractBignumData(q);
+       base = extractBignumData(g);
+}
+
+tz_data_type toTzDataType(const CKM::DataType dataType) {
+       switch (dataType) {
+       case CKM::DataType::BINARY_DATA:       return TYPE_GENERIC_SECRET;
+       case CKM::DataType::KEY_AES:           return TYPE_SKEY;
+       case CKM::DataType::KEY_DSA_PRIVATE:   return TYPE_AKEY_PRIVATE_DSA;
+       case CKM::DataType::KEY_RSA_PRIVATE:   return TYPE_AKEY_PRIVATE_RSA;
+       case CKM::DataType::KEY_ECDSA_PRIVATE: return TYPE_AKEY_PRIVATE_EC;
+       case CKM::DataType::KEY_DSA_PUBLIC:    return TYPE_AKEY_PUBLIC_DSA;
+       case CKM::DataType::KEY_RSA_PUBLIC:    return TYPE_AKEY_PUBLIC_RSA;
+       case CKM::DataType::KEY_ECDSA_PUBLIC:  return TYPE_AKEY_PUBLIC_EC;
+       default:
+               ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported,
+                       "Data type could not be imported by tz-backend");
+       }
+}
+
+tz_ec toTzEc(CKM::ElipticCurve ec)
+{
+       switch(ec) {
+       case CKM::ElipticCurve::prime192v1: return EC_NIST_P192;
+       case CKM::ElipticCurve::prime256v1: return EC_NIST_P256;
+       case CKM::ElipticCurve::secp384r1: return EC_NIST_P384;
+       default: ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "EC not supported by tz-backend");
+       }
+}
+
+tz_prf toTzPrf(CKM::KdfPrf prf)
+{
+       switch(prf) {
+       case CKM::KdfPrf::HMAC_SHA256: return PRF_HMAC_SHA256;
+       case CKM::KdfPrf::HMAC_SHA384: return PRF_HMAC_SHA384;
+       case CKM::KdfPrf::HMAC_SHA512: return PRF_HMAC_SHA512;
+       default: ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "PRF not supported by tz-backend");
+       }
+}
+
+tz_kbkdf_mode toTzKbkdfMode(CKM::KbkdfMode mode)
+{
+       switch(mode) {
+       case CKM::KbkdfMode::COUNTER: return KBKDF_MODE_COUNTER;
+       default:
+               ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported, "KBKDF mode not supported by tz-backend");
+       }
+}
+
+tz_kbkdf_ctr_loc toTzCtrLoc(CKM::KbkdfCounterLocation loc)
+{
+       switch(loc) {
+       case CKM::KbkdfCounterLocation::BEFORE_FIXED: return KBKDF_LOC_BEFORE_FIXED;
+       case CKM::KbkdfCounterLocation::AFTER_FIXED: return KBKDF_LOC_AFTER_FIXED;
+       case CKM::KbkdfCounterLocation::MIDDLE_FIXED: return KBKDF_LOC_MIDDLE_FIXED;
+       default:
+               ThrowErr(CKM::Exc::Crypto::DataTypeNotSupported,
+                       "KBKDF counter location not supported by tz-backend");
+       }
+}
+
+} // namespace
 
 namespace CKM {
 namespace Crypto {
 namespace TZ {
 namespace Internals {
 
-tz_algo_type getGenKeyType(AlgoType type)
+namespace {
+
+tz_algo_type getGenSKeyType(AlgoType type)
 {
        switch (type)
        {
@@ -52,95 +172,277 @@ tz_algo_type getAlgType(AlgoType type)
        case AlgoType::AES_CTR: return ALGO_AES_CTR;
        case AlgoType::AES_CFB: return ALGO_AES_CFB;
        case AlgoType::AES_GCM: return ALGO_AES_GCM;
+       case AlgoType::RSA_OAEP: return ALGO_RSA;
+       case AlgoType::RSA_SV: return ALGO_RSA_SV;
+       case AlgoType::DSA_SV: return ALGO_DSA_SV;
+       case AlgoType::ECDSA_SV: return ALGO_ECDSA_SV;
        default: ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
        };
 }
 
-tz_algo_type getAlgType(KeyType keyType)
+tz_hash_type getHashType(HashAlgorithm hash)
 {
-       switch (keyType)
+       switch (hash)
        {
-       case KeyType::KEY_AES:
-               return ALGO_AES_GEN;
-       case KeyType::KEY_RSA_PUBLIC:
-       case KeyType::KEY_RSA_PRIVATE:
-               return ALGO_RSA_GEN;
+       case HashAlgorithm::SHA1: return HASH_SHA1;
+       case HashAlgorithm::SHA256: return HASH_SHA256;
+       case HashAlgorithm::SHA384: return HASH_SHA384;
+       case HashAlgorithm::SHA512: return HASH_SHA512;
        default:
                ThrowErr(Exc::Crypto::OperationNotSupported, "Requested algorithm is not supported");
-       };
+       }
+}
+
+void decompose(const CryptoAlgorithm &alg,
+                          AlgoType &algo,
+                          uint32_t &ctrLenOrTagSizeBits,
+                          RawBuffer &iv,
+                          RawBuffer &aad)
+{
+       algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       switch (algo) {
+               case AlgoType::AES_CTR:
+                       iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
+                       ctrLenOrTagSizeBits = Params::DEFAULT_AES_IV_LEN * 8;
+                       alg.getParam(ParamName::ED_CTR_LEN, ctrLenOrTagSizeBits);
+                       // counter length is in bits
+                       if (ctrLenOrTagSizeBits != Params::DEFAULT_AES_IV_LEN * 8) {
+                               LogError("CTR length invalid: " << std::to_string(ctrLenOrTagSizeBits));
+                               ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
+                       }
+                       break;
+               case AlgoType::AES_CBC:
+                       iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
+                       break;
+               case AlgoType::AES_CFB:
+                       iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
+                       break;
+               case AlgoType::AES_GCM:
+                       iv = unpack<RawBuffer>(alg, ParamName::ED_IV);
+                       ctrLenOrTagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
+                       alg.getParam(ParamName::ED_TAG_LEN, ctrLenOrTagSizeBits);
+                       alg.getParam(ParamName::ED_AAD, aad);
+                       break;
+               case AlgoType::RSA_OAEP:
+                       break;
+               default:
+                       ThrowErr(Exc::Crypto::InputParam, "Invalid decryption algorithm");
+                       break;
+       }
 }
 
+} // namespace
+
 RawBuffer generateIV()
 {
        RawBuffer result;
-       TrustZoneContext::Instance().generateIV(Params::DEFAULT_AES_IV_LEN, result);
+       TrustZoneContext::Instance().generateIV(result);
        return result;
 }
 
-Data generateSKey(const CryptoAlgorithm &alg,
+void generateSKey(const CryptoAlgorithm &alg,
                                const Password &pwd,
                                const RawBuffer &iv,
-                               RawBuffer &tag)
+                               RawBuffer &tag,
+                               const RawBuffer &hash)
 {
        AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
        int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
 
-       Data keyData;
-       keyData.type = DataType(keyType);
-
        if (!pwd.empty()) {
                if (iv.empty()) {
                        ThrowErr(Exc::InputParam, "Key generation with password encryption requires an IV");
                }
 
                RawBuffer pwdBuf(pwd.begin(), pwd.end());
-               TrustZoneContext::Instance().generateSKeyPwd(getGenKeyType(keyType),
+               TrustZoneContext::Instance().generateSKeyPwd(getGenSKeyType(keyType),
                                                                                                        pwdBuf, iv, keyBits,
-                                                                                                       Params::DEFAULT_AES_GCM_TAG_LEN_BITS,
-                                                                                                       keyData.data, tag);
+                                                                                                       tag, hash);
        } else {
-               TrustZoneContext::Instance().generateSKey(getGenKeyType(keyType), keyBits,
-                                                                                               keyData.data);
+               TrustZoneContext::Instance().generateSKey(getGenSKeyType(keyType), keyBits,
+                                                                                               hash);
        }
 
-       return keyData;
 }
 
-DataPair generateAKey(const CryptoAlgorithm &,
-                                       const Password &,
-                                       const RawBuffer &)
+AlgoType generateAKey(const CryptoAlgorithm &alg,
+                                       const Password &pubPwd,
+                                       const Password &privPwd,
+                                       const RawBuffer &pubPwdIv,
+                                       const RawBuffer &privPwdIv,
+                                       RawBuffer &pubTag,
+                                       RawBuffer &privTag,
+                                       const RawBuffer &hashPriv,
+                                       const RawBuffer &hashPub)
 {
-       ThrowErr(Exc::Crypto::OperationNotSupported,
-                               "AKeys are not yet implemented in TrustZone backend");
+       AlgoType keyType = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+
+       RawBuffer pubPwdBuf;
+       if (!pubPwd.empty())
+               pubPwdBuf.assign(pubPwd.begin(), pubPwd.end());
+
+       RawBuffer privPwdBuf;
+       if (!privPwd.empty())
+               privPwdBuf.assign(privPwd.begin(), privPwd.end());
+
+       switch (keyType) {
+       case AlgoType::RSA_GEN: {
+               int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
+               TrustZoneContext::Instance().generateRSAKey(keyBits,
+                                                                                                       pubPwdBuf,
+                                                                                                       pubPwdIv,
+                                                                                                       privPwdBuf,
+                                                                                                       privPwdIv,
+                                                                                                       pubTag,
+                                                                                                       privTag,
+                                                                                                       hashPriv,
+                                                                                                       hashPub);
+               break;
+       }
+       case AlgoType::DSA_GEN: {
+               int keyBits = unpack<int>(alg, ParamName::GEN_KEY_LEN);
+               RawBuffer prime;
+               RawBuffer subprime;
+               RawBuffer base;
+               generateDSAParams(keyBits, prime, subprime, base);
+               TrustZoneContext::Instance().generateDSAKey(keyBits,
+                                                                                                       prime,
+                                                                                                       subprime,
+                                                                                                       base,
+                                                                                                       pubPwdBuf,
+                                                                                                       pubPwdIv,
+                                                                                                       privPwdBuf,
+                                                                                                       privPwdIv,
+                                                                                                       pubTag,
+                                                                                                       privTag,
+                                                                                                       hashPriv,
+                                                                                                       hashPub);
+               break;
+       }
+       case AlgoType::ECDSA_GEN: {
+               CKM::ElipticCurve ec = unpack<CKM::ElipticCurve>(alg, ParamName::GEN_EC);
+               TrustZoneContext::Instance().generateECKey(toTzEc(ec),
+                                                                                                  pubPwdBuf,
+                                                                                                  pubPwdIv,
+                                                                                                  privPwdBuf,
+                                                                                                  privPwdIv,
+                                                                                                  pubTag,
+                                                                                                  privTag,
+                                                                                                  hashPriv,
+                                                                                                  hashPub);
+               break;
+       }
+       default: {
+               ThrowErr(Exc::Crypto::InputParam,
+                       "Invalid algo type provided for generateAKey function");
+       }
+       }
+
+       return keyType;
 }
 
-void destroyKey(const RawBuffer &key)
+void destroyKey(const RawBuffer &keyId)
 {
-       TrustZoneContext::Instance().executeDestroy(key);
+       TrustZoneContext::Instance().executeDestroy(keyId);
 }
 
-RawBuffer importKey(const Data &data,
-                                       const Password &pwd,
-                                       const RawBuffer &iv,
-                                       RawBuffer &tag)
+void importData(const Data &data,
+                                        const EncryptionParams &encData,
+                                        const Password &pwd,
+                                        const RawBuffer &pwdIV,
+                                        RawBuffer &tag,
+                                        const RawBuffer &hash)
 {
-       tz_algo_type algo = getAlgType(data.type);
-       RawBuffer result;
+
+       const auto dataType = toTzDataType(data.type);
 
        RawBuffer pwdBuf(pwd.begin(), pwd.end());
        uint32_t keySizeBits = data.data.size() * 8;
-       TrustZoneContext::Instance().importKey(algo,
+       TrustZoneContext::Instance().importData(dataType,
                                                                                data.data,
+                                                                               encData,
                                                                                pwdBuf,
-                                                                               iv,
+                                                                               pwdIV,
                                                                                keySizeBits,
-                                                                               Params::DERIVED_KEY_LENGTH_BITS,
-                                                                               result,
-                                                                               tag);
+                                                                               tag,
+                                                                               hash);
+}
+
+void importWrappedKey(const RawBuffer &wrappingKeyId,
+                                         const Pwd &wrappingKeyPwd,
+                                         const CryptoAlgorithm &alg,
+                                         const Data &encryptedKey,
+                                         const Password &encryptedKeyPassword,
+                                         const RawBuffer &encryptedKeyIV,
+                                         RawBuffer &encryptedKeyTag,
+                                         const RawBuffer &encryptedKeyId)
+{
+       RawBuffer encryptedKeyPwdBuf(encryptedKeyPassword.begin(), encryptedKeyPassword.end());
+
+       AlgoType algo;
+       uint32_t ctrLenOrTagSizeBits = 0;
+       RawBuffer iv;
+       RawBuffer aad;
+       decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
+
+       // TODO it is awful!
+       TrustZoneContext::Instance().importWrappedKey(wrappingKeyId,
+                                                                                                 wrappingKeyPwd,
+                                                                                                 getAlgType(algo),
+                                                                                                 iv,
+                                                                                                 ctrLenOrTagSizeBits,
+                                                                                                 aad,
+                                                                                                 toTzDataType(encryptedKey.type),
+                                                                                                 encryptedKey.data,
+                                                                                                 encryptedKeyPwdBuf,
+                                                                                                 encryptedKeyIV,
+                                                                                                 encryptedKeyTag,
+                                                                                                 encryptedKeyId);
+}
+
+RawBuffer exportWrappedKey(const RawBuffer &wrappingKeyId,
+                                                  const Pwd &wrappingKeyPwd,
+                                                  const CryptoAlgorithm &alg,
+                                                  const RawBuffer &keyToWrapId,
+                                                  const Pwd &keyToWrapPwd,
+                                                  const DataType &keyToWrapType)
+{
+       AlgoType algo;
+       uint32_t ctrLenOrTagSizeBits = 0;
+       RawBuffer iv;
+       RawBuffer aad;
+       decompose(alg, algo, ctrLenOrTagSizeBits, iv, aad);
+
+       // TODO it is awful!
+       return TrustZoneContext::Instance().exportWrappedKey(wrappingKeyId,
+                                                                                                                wrappingKeyPwd,
+                                                                                                                getAlgType(algo),
+                                                                                                                iv,
+                                                                                                                ctrLenOrTagSizeBits,
+                                                                                                                aad,
+                                                                                                                keyToWrapId,
+                                                                                                                keyToWrapPwd,
+                                                                                                                toTzDataType(keyToWrapType));
+}
+
+RawBuffer getData(const RawBuffer &dataId,
+                                 const Pwd &pwd,
+                                 const DataType &type)
+{
+       RawBuffer result;
+       TrustZoneContext::Instance().getData(dataId,
+                                pwd,
+                                toTzDataType(type),
+                                result);
        return result;
 }
 
-BufferPair encryptDataAesGcm(const RawBuffer &key,
+void destroyData(const RawBuffer &dataId)
+{
+       TrustZoneContext::Instance().destroyData(dataId);
+}
+
+BufferPair encryptDataAesGcm(const RawBuffer &keyId,
                                                        const Pwd &pwd,
                                                        const RawBuffer &iv,
                                                        int tagSize,
@@ -150,26 +452,26 @@ BufferPair encryptDataAesGcm(const RawBuffer &key,
        RawBuffer result;
        RawBuffer tag;
 
-       TrustZoneContext::Instance().executeEncryptAE(key, pwd, iv, tagSize,
+       TrustZoneContext::Instance().executeEncryptAE(keyId, pwd, iv, tagSize,
                                                                                                aad, data, result, tag);
 
        return std::make_pair(result, tag);
 }
 
-RawBuffer encryptDataAesGcmPacked(const RawBuffer &key,
+RawBuffer encryptDataAesGcmPacked(const RawBuffer &keyId,
                                                                const Pwd &pwd,
                                                                const RawBuffer &iv,
                                                                int tagSize,
                                                                const RawBuffer &data,
                                                                const RawBuffer &aad)
 {
-       auto pair = encryptDataAesGcm(key, pwd, iv, tagSize, data, aad);
+       auto pair = encryptDataAesGcm(keyId, pwd, iv, tagSize, data, aad);
        std::copy(pair.second.begin(), pair.second.end(),
                        std::back_inserter(pair.first));
        return pair.first;
 }
 
-RawBuffer decryptDataAesGcm(const RawBuffer &key,
+RawBuffer decryptDataAesGcm(const RawBuffer &keyId,
                                                        const Pwd &pwd,
                                                        const RawBuffer &iv,
                                                        int tagSizeBits,
@@ -179,13 +481,13 @@ RawBuffer decryptDataAesGcm(const RawBuffer &key,
 {
        RawBuffer result;
 
-       TrustZoneContext::Instance().executeDecryptAE(key, pwd, iv, tagSizeBits,
+       TrustZoneContext::Instance().executeDecryptAE(keyId, pwd, iv, tagSizeBits,
                                                                                                tag, aad, data, result);
 
        return result;
 }
 
-RawBuffer decryptDataAesGcmPacked(const RawBuffer &key,
+RawBuffer decryptDataAesGcmPacked(const RawBuffer &keyId,
                                                                const Pwd &pwd,
                                                                const RawBuffer &iv,
                                                                int tagSizeBits,
@@ -197,7 +499,7 @@ RawBuffer decryptDataAesGcmPacked(const RawBuffer &key,
                ThrowErr(Exc::Crypto::InputParam, "Wrong size of tag");
 
        auto tagPos = data.data() + data.size() - tagSizeBytes;
-       return decryptDataAesGcm(key,
+       return decryptDataAesGcm(keyId,
                                                        pwd,
                                                        iv,
                                                        tagSizeBits,
@@ -207,30 +509,31 @@ RawBuffer decryptDataAesGcmPacked(const RawBuffer &key,
 }
 
 
-RawBuffer symmetricEncrypt(const RawBuffer &key,
+RawBuffer symmetricEncrypt(const RawBuffer &keyId,
                                                const Pwd &pwd,
                                                const CryptoAlgorithm &alg,
                                                const RawBuffer &data)
 {
        AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
-       uint64_t ctrLen = 0;
+       uint64_t ctrLen = Params::DEFAULT_AES_IV_LEN * 8;
 
        switch (algo) {
                case AlgoType::AES_CTR: {
-                       ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
+                       alg.getParam(ParamName::ED_CTR_LEN, ctrLen);
                        // counter length is in bits
                        if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
                                LogError("CTR length invalid: " << std::to_string(ctrLen));
                                ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
                        }
                        // no break here, we still need to slide down to executeCrypt
+                       fallthru;
                }
                case AlgoType::AES_CBC:
                case AlgoType::AES_CFB: {
                        RawBuffer result;
                        TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
                                                                                                        getAlgType(algo),
-                                                                                                       key,
+                                                                                                       keyId,
                                                                                                        pwd,
                                                                                                        unpack<RawBuffer>(alg, ParamName::ED_IV),
                                                                                                        data,
@@ -242,7 +545,7 @@ RawBuffer symmetricEncrypt(const RawBuffer &key,
                        alg.getParam(ParamName::ED_TAG_LEN, tagLenBits);
                        RawBuffer aad;
                        alg.getParam(ParamName::ED_AAD, aad);
-                       return encryptDataAesGcmPacked(key,
+                       return encryptDataAesGcmPacked(keyId,
                                                                                pwd,
                                                                                unpack<RawBuffer>(alg, ParamName::ED_IV),
                                                                                tagLenBits,
@@ -257,30 +560,31 @@ RawBuffer symmetricEncrypt(const RawBuffer &key,
                                "Incorrect algorithm provided for symmetric crypto operation");
 }
 
-RawBuffer symmetricDecrypt(const RawBuffer &key,
+RawBuffer symmetricDecrypt(const RawBuffer &keyId,
                                                const Pwd &pwd,
                                                const CryptoAlgorithm &alg,
                                                const RawBuffer &data)
 {
        AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
-       uint64_t ctrLen = 0;
+       uint64_t ctrLen = Params::DEFAULT_AES_IV_LEN * 8;
 
        switch (algo) {
                case AlgoType::AES_CTR: {
-                       ctrLen = unpack<uint64_t>(alg, ParamName::ED_CTR_LEN);
+                       alg.getParam(ParamName::ED_CTR_LEN, ctrLen);
                        // counter length is in bits
                        if (ctrLen != Params::DEFAULT_AES_IV_LEN * 8) {
                                LogError("CTR length invalid: " << std::to_string(ctrLen));
                                ThrowErr(Exc::Crypto::InputParam, "Invalid CTR length");
                        }
                        // no break here, we still need to slide down to executeCrypt
+                       fallthru;
                }
                case AlgoType::AES_CBC:
                case AlgoType::AES_CFB: {
                        RawBuffer result;
                        TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
                                                                                                        getAlgType(algo),
-                                                                                                       key,
+                                                                                                       keyId,
                                                                                                        pwd,
                                                                                                        unpack<RawBuffer>(alg, ParamName::ED_IV),
                                                                                                        data,
@@ -292,7 +596,7 @@ RawBuffer symmetricDecrypt(const RawBuffer &key,
                        alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
                        RawBuffer aad;
                        alg.getParam(ParamName::ED_AAD, aad);
-                       return decryptDataAesGcmPacked(key,
+                       return decryptDataAesGcmPacked(keyId,
                                                                                pwd,
                                                                                unpack<RawBuffer>(alg, ParamName::ED_IV),
                                                                                tagSizeBits,
@@ -307,41 +611,293 @@ RawBuffer symmetricDecrypt(const RawBuffer &key,
                                "Incorrect algorithm provided for symmetric crypto operation");
 }
 
-RawBuffer asymmetricEncrypt(const RawBuffer &,
-                                                       const Pwd &,
-                                                       const CryptoAlgorithm &,
-                                                       const RawBuffer &)
+RawBuffer asymmetricEncrypt(const RawBuffer &keyId,
+                                                       const Pwd &pwd,
+                                                       const CryptoAlgorithm &alg,
+                                                       const RawBuffer &data)
 {
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       RawBuffer result;
+
+       switch (algo)
+       {
+       case AlgoType::RSA_OAEP: {
+               TrustZoneContext::Instance().executeCrypt(CMD_ENCRYPT,
+                                                                                               getAlgType(algo),
+                                                                                               keyId,
+                                                                                               pwd,
+                                                                                               result, // unused dummy
+                                                                                               data,
+                                                                                               result);
+               return result;
+       }
+       default:
+               break;
+       }
+
        ThrowErr(Exc::Crypto::OperationNotSupported,
-                               "Asymmetric encryption is not yet supported on TrustZone backend");
+                               "Incorrect algorithm provided for asymmetric crypto operation");
 }
 
-RawBuffer asymmetricDecrypt(const RawBuffer &,
-                                                       const Pwd &,
-                                                       const CryptoAlgorithm &,
-                                                       const RawBuffer &)
+RawBuffer asymmetricDecrypt(const RawBuffer &keyId,
+                                                       const Pwd &pwd,
+                                                       const CryptoAlgorithm &alg,
+                                                       const RawBuffer &cipher)
 {
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       RawBuffer result;
+
+       switch (algo)
+       {
+       case AlgoType::RSA_OAEP: {
+               TrustZoneContext::Instance().executeCrypt(CMD_DECRYPT,
+                                                                                               getAlgType(algo),
+                                                                                               keyId,
+                                                                                               pwd,
+                                                                                               result, // unused dummy
+                                                                                               cipher,
+                                                                                               result);
+               return result;
+       }
+       default:
+               break;
+       }
+
        ThrowErr(Exc::Crypto::OperationNotSupported,
-                               "Asymmetric encryption is not yet supported on TrustZone backend");
+                               "Incorrect algorithm provided for asymmetric crypto operation");
 }
 
-RawBuffer sign(const RawBuffer &,
-                       const Pwd &,
-                       const CryptoAlgorithm &,
-                       const RawBuffer &)
+uint32_t initCipher(const RawBuffer &keyId,
+                                       const Pwd &pwd,
+                                       const CryptoAlgorithm &alg,
+                                       bool encrypt)
 {
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+
+       switch (algo)
+       {
+       case AlgoType::AES_GCM: {
+               int tagSizeBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS;
+               alg.getParam(ParamName::ED_TAG_LEN, tagSizeBits);
+               RawBuffer aad;
+               alg.getParam(ParamName::ED_AAD, aad);
+               return TrustZoneContext::Instance().initGcmCipher(encrypt ? CIPHER_ENCRYPT : CIPHER_DECRYPT,
+                                                                                                                 keyId,
+                                                                                                                 pwd,
+                                                                                                                 unpack<RawBuffer>(alg, ParamName::ED_IV),
+                                                                                                                 tagSizeBits,
+                                                                                                                 aad);
+       }
+       case AlgoType::AES_CBC:
+       case AlgoType::AES_CTR:
+       case AlgoType::AES_CFB:
+               // TODO optionally implement above modes as well
+       default:
+               break;
+       };
+
        ThrowErr(Exc::Crypto::OperationNotSupported,
-                               "Certificate signing is not yet supported on TrustZone backend");
+                        "Incorrect algorithm provided for symmetric crypto operation");
 }
 
-int verify(const RawBuffer &,
-               const Pwd &,
-               const CryptoAlgorithm &,
-               const RawBuffer &,
-               const RawBuffer &)
+void addAAD(uint32_t opId,
+                       const RawBuffer &aad)
 {
-       ThrowErr(Exc::Crypto::OperationNotSupported,
-                               "Certificate signing is not yet supported on TrustZone backend");
+       TrustZoneContext::Instance().addGcmAAD(opId, aad);
+}
+
+RawBuffer updateCipher(uint32_t opId,
+                                          const RawBuffer &data)
+{
+       return TrustZoneContext::Instance().updateGcmCipher(opId, data);
+}
+
+RawBuffer finalizeCipher(uint32_t opId,
+                                                const RawBuffer &data)
+{
+       return TrustZoneContext::Instance().finalizeGcmCipher(opId, data);
+}
+
+void cleanupCipher(uint32_t opId)
+{
+       return TrustZoneContext::Instance().cleanupCipher(opId);
+}
+
+RawBuffer sign(const RawBuffer &pkeyId,
+                       const Pwd &pwd,
+                       const CryptoAlgorithm &alg,
+                       const RawBuffer &message)
+{
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
+       if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
+               ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
+
+       RawBuffer signature;
+       TrustZoneContext::Instance().executeSign(getAlgType(algo),
+                                                                                       getHashType(hash),
+                                                                                       pkeyId,
+                                                                                       pwd,
+                                                                                       message,
+                                                                                       signature);
+       return signature;
+}
+
+int verify(const RawBuffer &pkeyId,
+               const Pwd &pwd,
+               const CryptoAlgorithm &alg,
+               const RawBuffer &message,
+               const RawBuffer &signature)
+{
+       AlgoType algo = unpack<AlgoType>(alg, ParamName::ALGO_TYPE);
+       HashAlgorithm hash = unpack<HashAlgorithm>(alg, ParamName::SV_HASH_ALGO);
+       if (algo != AlgoType::RSA_SV && hash == HashAlgorithm::NONE)
+               ThrowErr(Exc::Crypto::InputParam, "Only RSA supports no hash option");
+
+       return TrustZoneContext::Instance().executeVerify(getAlgType(algo),
+                                                                                                       getHashType(hash),
+                                                                                                       pkeyId,
+                                                                                                       pwd,
+                                                                                                       message,
+                                                                                                       signature);
+}
+
+void deriveECDH(const RawBuffer &prvKeyId,
+                               const Pwd &prvKeyPwd,
+                               const RawBuffer &pubKey,
+                               const Password &secretPwd,
+                               const RawBuffer &secretPwdIV,
+                               RawBuffer &secretTag,
+                               const RawBuffer &secretHash)
+{
+       auto peerKey = std::make_shared<KeyImpl>(pubKey);
+       if (peerKey->getType() != KeyType::KEY_ECDSA_PUBLIC)
+               ThrowErr(Exc::Crypto::InputParam, "ECDH requires peer's public EC key");
+       auto peerEvp = peerKey->getEvpShPtr().get();
+       assert(peerEvp);
+
+       int subType = EVP_PKEY_type(EVP_PKEY_id(peerEvp));
+       if (subType != EVP_PKEY_EC)
+               ThrowErr(Exc::Crypto::InputParam, "Invalid key type: ", subType);
+
+       auto ecKey = EVP_PKEY_get0_EC_KEY(peerEvp);
+       if (!ecKey)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC key");
+
+       auto ecPoint = EC_KEY_get0_public_key(ecKey);
+       if (!ecPoint)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC public key");
+
+       auto ecGroup = EC_KEY_get0_group(ecKey);
+       if (!ecGroup)
+               ThrowErr(Exc::Crypto::InternalError, "Can't get EC group");
+
+       BIGNUM *x = BN_new();
+       BIGNUM *y = BN_new();
+       if (!EC_POINT_get_affine_coordinates(ecGroup, ecPoint, x, y, NULL))
+               ThrowErr(Exc::Crypto::InternalError, "Failed to get EC pub key coordinates");
+
+       auto xBuf = extractBignumData(x);
+       auto yBuf = extractBignumData(y);
+
+       RawBuffer secretPwdBuf(secretPwd.begin(), secretPwd.end());
+
+       int pubCurve = EC_GROUP_get_curve_name(ecGroup);
+       tz_ec tzCurve;
+       switch (pubCurve)
+       {
+       case NID_X9_62_prime192v1:
+               tzCurve = EC_NIST_P192;
+               break;
+
+       case NID_X9_62_prime256v1:
+               tzCurve = EC_NIST_P256;
+               break;
+
+       case NID_secp384r1:
+               tzCurve = EC_NIST_P384;
+               break;
+
+       default:
+               ThrowErr(Exc::Crypto::InputParam, "Unsupported public key EC");
+       }
+
+       TrustZoneContext::Instance().executeEcdh(prvKeyId,
+                                                                                        prvKeyPwd,
+                                                                                        tzCurve,
+                                                                                        xBuf,
+                                                                                        yBuf,
+                                                                                        secretPwdBuf,
+                                                                                        secretPwdIV,
+                                                                                        secretTag,
+                                                                                        secretHash);
+}
+
+void deriveKBKDF(const RawBuffer &secretId,
+                                const Pwd &secretPwd,
+                                const CryptoAlgorithm &alg,
+                                const Password &keyPwd,
+                                const RawBuffer &keyPwdIV,
+                                RawBuffer &keyTag,
+                                const RawBuffer &keyHash)
+{
+       RawBuffer label, context, fixed;
+       KbkdfCounterLocation counterLocation;
+       KdfPrf prf;
+       KbkdfMode mode;
+       size_t length, rlenBits = 32, llenBits = 32, tmp;
+       bool hasLabel = alg.getParam(ParamName::KBKDF_LABEL, label);
+       bool hasContext = alg.getParam(ParamName::KBKDF_CONTEXT, context);
+       bool hasFixed = alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed);
+       alg.getParam(ParamName::KBKDF_COUNTER_LOCATION, counterLocation);
+       alg.getParam(ParamName::KBKDF_MODE, mode);
+       alg.getParam(ParamName::KDF_PRF, prf);
+       alg.getParam(ParamName::KDF_LEN, length);
+       alg.getParam(ParamName::KBKDF_RLEN, rlenBits);
+       bool hasLLen = alg.getParam(ParamName::KBKDF_LLEN, llenBits);
+       bool noSeparator = alg.getParam(ParamName::KBKDF_NO_SEPARATOR, tmp);
+
+       RawBuffer key;
+       if (hasFixed) {
+               if (hasLabel || hasContext || noSeparator || hasLLen ||
+                       counterLocation == KbkdfCounterLocation::MIDDLE_FIXED)
+                       ThrowErr(Exc::Crypto::InputParam, "Unexpected parameters for fixed input mode.");
+       } else {
+               if (!hasLabel || !hasContext)
+                       ThrowErr(Exc::Crypto::InputParam, "Missing label and/or context.");
+
+               if (llenBits != 0 && llenBits != 8 && llenBits != 16 && llenBits != 24 && llenBits != 32)
+                       ThrowErr(Exc::Crypto::InputParam, "Invalid llen value");
+       }
+       if (length != 16 && length != 24 && length != 32)
+               ThrowErr(Exc::Crypto::InputParam, "Invalid key length");
+
+       if (rlenBits != 8 && rlenBits != 16 && rlenBits != 24 && rlenBits != 32)
+               ThrowErr(Exc::Crypto::InputParam, "Invalid rlen value");
+
+       RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end());
+
+       TrustZoneContext::Instance().executeKbkdf(secretId,
+                                                                                         secretPwd,
+                                                                                         length,
+                                                                                         label,
+                                                                                         context,
+                                                                                         fixed,
+                                                                                         toTzPrf(prf),
+                                                                                         toTzKbkdfMode(mode),
+                                                                                         toTzCtrLoc(counterLocation),
+                                                                                         rlenBits,
+                                                                                         llenBits,
+                                                                                         noSeparator,
+                                                                                         keyPwdBuf,
+                                                                                         keyPwdIV,
+                                                                                         keyTag,
+                                                                                         keyHash);
+}
+
+size_t maxChunkSize()
+{
+       return TrustZoneContext::Instance().getMaxChunkSize();
 }
 
 } // namespace Internals