Add packed-c protocol support for crypto service

To provide a lightweight parameter encoding that is aligned to
conventions used by SCMI, the packed-c parameter serialization has
been added to the crypto service.  This builds on generic
components that allow other packed-c service access protocols
to be added easily.  Service level tests have been extended to
use both protobuf and packed-c clients.

Signed-off-by: julhal01 <julian.hall@arm.com>
Change-Id: I9279b0814bcc9cf6c4aa4e30629e2f46f2df4c23
diff --git a/components/service/crypto/client/cpp/crypto_client.cpp b/components/service/crypto/client/cpp/crypto_client.cpp
index b27a585..602a6b5 100644
--- a/components/service/crypto/client/cpp/crypto_client.cpp
+++ b/components/service/crypto/client/cpp/crypto_client.cpp
@@ -4,27 +4,8 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <cstring>
-#include <cstdlib>
 #include "crypto_client.h"
 #include <protocols/rpc/common/packed-c/status.h>
-#include <service/common/serializer/protobuf/pb_helper.h>
-#include <rpc_caller.h>
-#include <service/crypto/protobuf/opcodes.pb.h>
-#include <service/crypto/protobuf/generate_key.pb.h>
-#include <service/crypto/protobuf/destroy_key.pb.h>
-#include <service/crypto/protobuf/import_key.pb.h>
-#include <service/crypto/protobuf/open_key.pb.h>
-#include <service/crypto/protobuf/close_key.pb.h>
-#include <service/crypto/protobuf/export_key.pb.h>
-#include <service/crypto/protobuf/export_public_key.pb.h>
-#include <service/crypto/protobuf/sign_hash.pb.h>
-#include <service/crypto/protobuf/verify_hash.pb.h>
-#include <service/crypto/protobuf/asymmetric_encrypt.pb.h>
-#include <service/crypto/protobuf/asymmetric_decrypt.pb.h>
-#include <service/crypto/protobuf/generate_random.pb.h>
-#include <pb_encode.h>
-#include <pb_decode.h>
 
 crypto_client::crypto_client() :
     m_caller(NULL),
@@ -54,758 +35,3 @@
 {
     return m_err_rpc_status;
 }
-
-psa_status_t crypto_client::generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_GenerateKeyIn req_msg = ts_crypto_GenerateKeyIn_init_default;
-
-    translate_key_attributes(req_msg.attributes, *attributes);
-    req_msg.has_attributes = true;
-
-    if (pb_get_encoded_size(&req_len, ts_crypto_GenerateKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_GenerateKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_GENERATE_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    ts_crypto_GenerateKeyOut resp_msg = ts_crypto_GenerateKeyOut_init_default;
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_GenerateKeyOut_fields, &resp_msg)) {
-
-                        *handle = resp_msg.handle;
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::destroy_key(psa_key_handle_t handle)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_DestroyKeyIn req_msg = ts_crypto_DestroyKeyIn_init_default;
-
-    req_msg.handle = handle;
-
-    if (pb_get_encoded_size(&req_len, ts_crypto_DestroyKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_DestroyKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_DESTROY_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::open_key(psa_key_id_t id, psa_key_handle_t *handle)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_OpenKeyIn req_msg = ts_crypto_OpenKeyIn_init_default;
-    req_msg.id = id;
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_OpenKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_OpenKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                        ts_crypto_Opcode_OPEN_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    ts_crypto_OpenKeyOut resp_msg = ts_crypto_OpenKeyOut_init_default;
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_OpenKeyOut_fields, &resp_msg)) {
-
-                        *handle = resp_msg.handle;
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::close_key(psa_key_handle_t handle)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_CloseKeyIn req_msg = ts_crypto_CloseKeyIn_init_default;
-
-    req_msg.handle = handle;
-
-    if (pb_get_encoded_size(&req_len, ts_crypto_CloseKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_CloseKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_CLOSE_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::import_key(const psa_key_attributes_t *attributes,
-                        const uint8_t *data, size_t data_length, psa_key_handle_t *handle)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_ImportKeyIn req_msg = ts_crypto_ImportKeyIn_init_default;
-    pb_bytes_array_t *key_byte_array = pb_malloc_byte_array_containing_bytes(data, data_length);
-
-    translate_key_attributes(req_msg.attributes, *attributes);
-    req_msg.has_attributes = true;
-    req_msg.data = pb_out_byte_array(key_byte_array);
-
-    if (pb_get_encoded_size(&req_len, ts_crypto_ImportKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_ImportKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_IMPORT_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    ts_crypto_ImportKeyOut resp_msg = ts_crypto_ImportKeyOut_init_default;
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_ImportKeyOut_fields, &resp_msg)) {
-
-                        *handle = resp_msg.handle;
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    ::free(key_byte_array);
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::export_key(psa_key_handle_t handle,
-                        uint8_t *data, size_t data_size,
-                        size_t *data_length)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_ExportKeyIn req_msg = ts_crypto_ExportKeyIn_init_default;
-    req_msg.handle = handle;
-
-    *data_length = 0; /* For failure case */
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_ExportKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_ExportKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_EXPORT_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    ts_crypto_ExportKeyOut resp_msg = ts_crypto_ExportKeyOut_init_default;
-                    pb_bytes_array_t *exported_key = pb_malloc_byte_array(resp_len);
-
-                    if (exported_key) {
-
-                        resp_msg.data = pb_in_byte_array(exported_key);
-                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                        if (pb_decode(&istream, ts_crypto_ExportKeyOut_fields, &resp_msg)) {
-
-                            if (exported_key->size <= data_size) {
-
-                                memcpy(data, exported_key->bytes, exported_key->size);
-                                *data_length = exported_key->size;
-                            }
-                            else {
-                                /* Provided buffer is too small */
-                                psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
-                            }
-                        }
-                        else {
-                            /* Failed to decode response message */
-                            psa_status = PSA_ERROR_GENERIC_ERROR;
-                        }
-
-                        ::free(exported_key);
-                    }
-                    else {
-                        /* Failed to allocate buffer for exported key */
-                        psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
-                    }
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::export_public_key(psa_key_handle_t handle,
-                                uint8_t *data, size_t data_size, size_t *data_length)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_ExportPublicKeyIn req_msg = ts_crypto_ExportPublicKeyIn_init_default;
-    req_msg.handle = handle;
-
-    *data_length = 0; /* For failure case */
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_ExportPublicKeyIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_ExportPublicKeyIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                ts_crypto_Opcode_EXPORT_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    ts_crypto_ExportPublicKeyOut resp_msg = ts_crypto_ExportPublicKeyOut_init_default;
-                    pb_bytes_array_t *exported_key = pb_malloc_byte_array(resp_len);
-
-                    if (exported_key) {
-
-                        resp_msg.data = pb_in_byte_array(exported_key);
-                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                        if (pb_decode(&istream, ts_crypto_ExportPublicKeyOut_fields, &resp_msg)) {
-
-                            if (exported_key->size <= data_size) {
-
-                                memcpy(data, exported_key->bytes, exported_key->size);
-                                *data_length = exported_key->size;
-                            }
-                            else {
-                                /* Provided buffer is too small */
-                                psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
-                            }
-                        }
-                        else {
-                            /* Failed to decode response message */
-                            psa_status = PSA_ERROR_GENERIC_ERROR;
-                        }
-
-                        ::free(exported_key);
-                    }
-                    else {
-                        /* Failed to alloocate buffer for exported key */
-                        psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
-                    }
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            uint8_t *signature, size_t signature_size, size_t *signature_length)
-{
-    size_t req_len;
-    pb_bytes_array_t *hash_byte_array = pb_malloc_byte_array_containing_bytes(hash, hash_length);
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_SignHashIn req_msg = ts_crypto_SignHashIn_init_default;
-
-    *signature_length = 0;  /* For failure case */
-
-    req_msg.handle = handle;
-    req_msg.alg = alg;
-	req_msg.hash = pb_out_byte_array(hash_byte_array);
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_SignHashIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_SignHashIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                        ts_crypto_Opcode_SIGN_HASH, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    pb_bytes_array_t *sig_byte_array = pb_malloc_byte_array(PSA_SIGNATURE_MAX_SIZE);
-                    ts_crypto_SignHashOut resp_msg = ts_crypto_SignHashOut_init_default;
-                    resp_msg.signature = pb_in_byte_array(sig_byte_array);
-
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_SignHashOut_fields, &resp_msg)) {
-
-                        if (sig_byte_array->size <= signature_size) {
-
-                            memcpy(signature, sig_byte_array->bytes, sig_byte_array->size);
-                            *signature_length = sig_byte_array->size;
-                        }
-                        else {
-                            /* Provided buffer is too small */
-                            psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
-                        }
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-
-                    ::free(sig_byte_array);
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    ::free(hash_byte_array);
-
-    return psa_status;
-}
-
-
-psa_status_t crypto_client::verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
-                        const uint8_t *hash, size_t hash_length,
-                        const uint8_t *signature, size_t signature_length)
-{
-    size_t req_len;
-    pb_bytes_array_t *hash_byte_array = pb_malloc_byte_array_containing_bytes(hash, hash_length);
-    pb_bytes_array_t *sig_byte_array = pb_malloc_byte_array_containing_bytes(signature, signature_length);
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_VerifyHashIn req_msg = ts_crypto_VerifyHashIn_init_default;
-
-    req_msg.handle = handle;
-    req_msg.alg = alg;
-	req_msg.hash = pb_out_byte_array(hash_byte_array);
-    req_msg.signature = pb_out_byte_array(sig_byte_array);
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_VerifyHashIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_VerifyHashIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                        ts_crypto_Opcode_VERIFY_HASH, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    ::free(hash_byte_array);
-    ::free(sig_byte_array);
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
-                        const uint8_t *input, size_t input_length,
-                        const uint8_t *salt, size_t salt_length,
-                        uint8_t *output, size_t output_size, size_t *output_length)
-{
-    size_t req_len;
-    pb_bytes_array_t *plaintext_byte_array = pb_malloc_byte_array_containing_bytes(input, input_length);
-    pb_bytes_array_t *salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_AsymmetricEncryptIn req_msg = ts_crypto_AsymmetricEncryptIn_init_default;
-
-    *output_length = 0;  /* For failure case */
-
-    req_msg.handle = handle;
-    req_msg.alg = alg;
-	req_msg.plaintext = pb_out_byte_array(plaintext_byte_array);
-    req_msg.salt = pb_out_byte_array(salt_byte_array);
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricEncryptIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus = PSA_ERROR_GENERIC_ERROR;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_AsymmetricEncryptIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                        ts_crypto_Opcode_ASYMMETRIC_ENCRYPT, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    pb_bytes_array_t *ciphertext_byte_array = pb_malloc_byte_array(output_size);
-                    ts_crypto_AsymmetricEncryptOut resp_msg = ts_crypto_AsymmetricEncryptOut_init_default;
-                    resp_msg.ciphertext = pb_in_byte_array(ciphertext_byte_array);
-
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
-
-                        if (ciphertext_byte_array->size <= output_size) {
-
-                            memcpy(output, ciphertext_byte_array->bytes, ciphertext_byte_array->size);
-                            *output_length = ciphertext_byte_array->size;
-                        }
-                        else {
-                            /* Provided buffer is too small */
-                            psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
-                        }
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-
-                    ::free(ciphertext_byte_array);
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    ::free(plaintext_byte_array);
-    ::free(salt_byte_array);
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
-                        const uint8_t *input, size_t input_length,
-                        const uint8_t *salt, size_t salt_length,
-                        uint8_t *output, size_t output_size, size_t *output_length)
-{
-    size_t req_len;
-    pb_bytes_array_t *ciphertext_byte_array = pb_malloc_byte_array_containing_bytes(input, input_length);
-    pb_bytes_array_t *salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_AsymmetricDecryptIn req_msg = ts_crypto_AsymmetricDecryptIn_init_default;
-
-    *output_length = 0;  /* For failure case */
-
-    req_msg.handle = handle;
-    req_msg.alg = alg;
-	req_msg.ciphertext = pb_out_byte_array(ciphertext_byte_array);
-    req_msg.salt = pb_out_byte_array(salt_byte_array);
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricDecryptIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_AsymmetricDecryptIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                        ts_crypto_Opcode_ASYMMETRIC_DECRYPT, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    pb_bytes_array_t *plaintext_byte_array = pb_malloc_byte_array(output_size);
-                    ts_crypto_AsymmetricDecryptOut resp_msg = ts_crypto_AsymmetricDecryptOut_init_default;
-                    resp_msg.plaintext = pb_in_byte_array(plaintext_byte_array);
-
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
-
-                        if (plaintext_byte_array->size <= output_size) {
-
-                            memcpy(output, plaintext_byte_array->bytes, plaintext_byte_array->size);
-                            *output_length = plaintext_byte_array->size;
-                        }
-                        else {
-                            /* Provided buffer is too small */
-                            m_err_rpc_status = PSA_ERROR_BUFFER_TOO_SMALL;
-                        }
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        m_err_rpc_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-
-                    ::free(plaintext_byte_array);
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    ::free(ciphertext_byte_array);
-    ::free(salt_byte_array);
-
-    return psa_status;
-}
-
-psa_status_t crypto_client::generate_random(uint8_t *output, size_t output_size)
-{
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_GenerateRandomIn req_msg = ts_crypto_GenerateRandomIn_init_default;
-
-    req_msg.size = output_size;
-
-	if (pb_get_encoded_size(&req_len, ts_crypto_GenerateRandomIn_fields, &req_msg)) {
-
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
-
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
-
-        if (call_handle) {
-
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
-
-            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
-            pb_encode(&ostream, ts_crypto_GenerateRandomIn_fields, &req_msg);
-
-            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
-                    ts_crypto_Opcode_GENERATE_RANDOM, &opstatus, &resp_buf, &resp_len);
-
-            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
-
-                psa_status = opstatus;
-
-                if (psa_status == PSA_SUCCESS) {
-
-                    pb_bytes_array_t *output_byte_array = pb_malloc_byte_array(output_size);
-                    ts_crypto_GenerateRandomOut resp_msg = ts_crypto_GenerateRandomOut_init_default;
-                    resp_msg.random_bytes = pb_in_byte_array(output_byte_array);
-
-                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
-
-                    if (pb_decode(&istream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
-
-                        if (output_byte_array->size == output_size) {
-
-                            memcpy(output, output_byte_array->bytes, output_byte_array->size);
-                        }
-                        else {
-                            /* Mismatch between requested and generated length */
-                            psa_status = PSA_ERROR_GENERIC_ERROR;
-                        }
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-
-                    ::free(output_byte_array);
-                }
-            }
-
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
-
-    return psa_status;
-}
-
-void crypto_client::translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
-                            const psa_key_attributes_t &psa_attributes)
-{
-    proto_attributes.type = psa_get_key_type(&psa_attributes);
-    proto_attributes.key_bits = psa_get_key_bits(&psa_attributes);
-    proto_attributes.lifetime = psa_get_key_lifetime(&psa_attributes);
-    proto_attributes.id = psa_get_key_id(&psa_attributes);
-
-    proto_attributes.has_policy = true;
-    proto_attributes.policy.usage = psa_get_key_usage_flags(&psa_attributes);
-    proto_attributes.policy.alg = psa_get_key_algorithm(&psa_attributes);
- }
diff --git a/components/service/crypto/client/cpp/crypto_client.h b/components/service/crypto/client/cpp/crypto_client.h
index 3d0366f..5f6f0e1 100644
--- a/components/service/crypto/client/cpp/crypto_client.h
+++ b/components/service/crypto/client/cpp/crypto_client.h
@@ -9,66 +9,61 @@
 
 #include <cstdint>
 #include <psa/crypto.h>
-#include <service/crypto/protobuf/key_attributes.pb.h>
-
 
 struct rpc_caller;
 
-/** Provides a client interface for accessing an instance of the PSA Crypto service.
- **/
+/*
+ * Provides a client interface for accessing an instance of the Crypto service
+ * using a C++ version of the PSA Crypto API.
+ */
 class crypto_client
 {
 public:
-    crypto_client(struct rpc_caller *caller);
     virtual ~crypto_client();
 
     int err_rpc_status() const;
 
     /* Key lifecycle methods */
-    psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle);
-    psa_status_t destroy_key(psa_key_handle_t handle);
-    psa_status_t open_key(psa_key_id_t id, psa_key_handle_t *handle);
-    psa_status_t close_key(psa_key_handle_t handle);
-    psa_status_t import_key(const psa_key_attributes_t *attributes,
-                            const uint8_t *data, size_t data_length, psa_key_handle_t *handle);
+    virtual psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle) = 0;
+    virtual psa_status_t destroy_key(psa_key_handle_t handle) = 0;
+    virtual psa_status_t open_key(psa_key_id_t id, psa_key_handle_t *handle) = 0;
+    virtual psa_status_t close_key(psa_key_handle_t handle) = 0;
+    virtual psa_status_t import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data, size_t data_length, psa_key_handle_t *handle) = 0;
 
     /* Key export methods */
-    psa_status_t export_key(psa_key_handle_t handle,
+    virtual psa_status_t export_key(psa_key_handle_t handle,
                             uint8_t *data, size_t data_size,
-                            size_t *data_length);
-    psa_status_t export_public_key(psa_key_handle_t handle,
-                            uint8_t *data, size_t data_size, size_t *data_length);
+                            size_t *data_length) = 0;
+    virtual psa_status_t export_public_key(psa_key_handle_t handle,
+                            uint8_t *data, size_t data_size, size_t *data_length) = 0;
 
     /* Sign/verify methods */
-    psa_status_t sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+    virtual psa_status_t sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
                             const uint8_t *hash, size_t hash_length,
-                            uint8_t *signature, size_t signature_size, size_t *signature_length);
-    psa_status_t verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            uint8_t *signature, size_t signature_size, size_t *signature_length) = 0;
+    virtual psa_status_t verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
                             const uint8_t *hash, size_t hash_length,
-                            const uint8_t *signature, size_t signature_length);
+                            const uint8_t *signature, size_t signature_length) = 0;
 
     /* Asymmetric encrypt/decrypt */
-    psa_status_t asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+    virtual psa_status_t asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
                             const uint8_t *input, size_t input_length,
                             const uint8_t *salt, size_t salt_length,
-                            uint8_t *output, size_t output_size, size_t *output_length);
-    psa_status_t asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                            uint8_t *output, size_t output_size, size_t *output_length) = 0;
+    virtual psa_status_t asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
                             const uint8_t *input, size_t input_length,
                             const uint8_t *salt, size_t salt_length,
-                            uint8_t *output, size_t output_size, size_t *output_length);
+                            uint8_t *output, size_t output_size, size_t *output_length) = 0;
 
     /* Random number generation */
-    psa_status_t generate_random(uint8_t *output, size_t output_size);
+    virtual psa_status_t generate_random(uint8_t *output, size_t output_size) = 0;
 
 protected:
     crypto_client();
+    crypto_client(struct rpc_caller *caller);
     void set_caller(struct rpc_caller *caller);
 
-private:
-
-    void translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
-                            const psa_key_attributes_t &psa_attributes);
-
     struct rpc_caller *m_caller;
     int m_err_rpc_status;
 };
diff --git a/components/service/crypto/client/cpp/packed-c/component.cmake b/components/service/crypto/client/cpp/packed-c/component.cmake
new file mode 100644
index 0000000..7ad58ab
--- /dev/null
+++ b/components/service/crypto/client/cpp/packed-c/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/packedc_crypto_client.cpp"
+	)
+
diff --git a/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.cpp b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.cpp
new file mode 100644
index 0000000..e0e85e0
--- /dev/null
+++ b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.cpp
@@ -0,0 +1,749 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include <cstdlib>
+#include "packedc_crypto_client.h"
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/asymmetric_decrypt.h>
+#include <protocols/service/crypto/packed-c/asymmetric_encrypt.h>
+#include <protocols/service/crypto/packed-c/close_key.h>
+#include <protocols/service/crypto/packed-c/destroy_key.h>
+#include <protocols/service/crypto/packed-c/export_key.h>
+#include <protocols/service/crypto/packed-c/export_public_key.h>
+#include <protocols/service/crypto/packed-c/generate_key.h>
+#include <protocols/service/crypto/packed-c/generate_random.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include <protocols/service/crypto/packed-c/open_key.h>
+#include <protocols/service/crypto/packed-c/sign_hash.h>
+#include <protocols/service/crypto/packed-c/verify_hash.h>
+#include <common/tlv/tlv.h>
+#include <rpc_caller.h>
+
+
+packedc_crypto_client::packedc_crypto_client() :
+    crypto_client()
+{
+
+}
+
+packedc_crypto_client::packedc_crypto_client(struct rpc_caller *caller) :
+    crypto_client(caller)
+{
+
+}
+
+packedc_crypto_client::~packedc_crypto_client()
+{
+
+}
+
+psa_status_t packedc_crypto_client::generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_generate_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_generate_key_in);
+
+    translate_key_attributes(req_msg.attributes, *attributes);
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_GENERATE_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                if (resp_len >= sizeof(ts_crypto_generate_key_out)) {
+
+                    struct ts_crypto_generate_key_out resp_msg;
+                    memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_generate_key_out));
+                    *handle = resp_msg.handle;
+                }
+                else {
+                    /* Failed to decode response message */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::destroy_key(psa_key_handle_t handle)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_destroy_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_destroy_key_in);
+
+    req_msg.handle = handle;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_DESTROY_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::open_key(psa_key_id_t id, psa_key_handle_t *handle)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_open_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_open_key_in);
+
+    req_msg.id = id;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    TS_CRYPTO_OPCODE_OPEN_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                if (resp_len >= sizeof(ts_crypto_open_key_out)) {
+
+                    struct ts_crypto_open_key_out resp_msg;
+                    memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_open_key_out));
+                    *handle = resp_msg.handle;
+                }
+                else {
+                    /* Failed to decode response message */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::close_key(psa_key_handle_t handle)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_close_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_close_key_in);
+
+    req_msg.handle = handle;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_CLOSE_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::import_key(const psa_key_attributes_t *attributes,
+                        const uint8_t *data, size_t data_length, psa_key_handle_t *handle)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_import_key_in req_msg;
+    size_t req_fixed_len = sizeof(ts_crypto_import_key_in);
+    size_t req_len = req_fixed_len + tlv_required_space(data_length);
+
+    translate_key_attributes(req_msg.attributes, *attributes);
+
+    struct tlv_record key_record;
+    key_record.tag = TS_CRYPTO_IMPORT_KEY_IN_TAG_DATA;
+    key_record.length = data_length;
+    key_record.value = data;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_fixed_len);
+
+        tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+        tlv_encode(&req_iter, &key_record);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_IMPORT_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                if (resp_len >= sizeof(ts_crypto_open_key_out)) {
+
+                    struct ts_crypto_import_key_out resp_msg;
+                    memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_import_key_out));
+                    *handle = resp_msg.handle;
+                }
+                else {
+                    /* Failed to decode response message */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::export_key(psa_key_handle_t handle,
+                        uint8_t *data, size_t data_size,
+                        size_t *data_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_export_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_export_key_in);
+
+    req_msg.handle = handle;
+
+    *data_length = 0; /* For failure case */
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_EXPORT_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_EXPORT_KEY_OUT_TAG_DATA, &decoded_record)) {
+
+                    if (decoded_record.length <= data_size) {
+
+                        memcpy(data, decoded_record.value, decoded_record.length);
+                        *data_length = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::export_public_key(psa_key_handle_t handle,
+                                uint8_t *data, size_t data_size, size_t *data_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_export_public_key_in req_msg;
+    size_t req_len = sizeof(ts_crypto_export_public_key_in);
+
+    req_msg.handle = handle;
+
+    *data_length = 0; /* For failure case */
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+            TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_EXPORT_PUBLIC_KEY_OUT_TAG_DATA, &decoded_record)) {
+
+                    if (decoded_record.length <= data_size) {
+
+                        memcpy(data, decoded_record.value, decoded_record.length);
+                        *data_length = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_sign_hash_in req_msg;
+    size_t req_fixed_len = sizeof(ts_crypto_sign_hash_in);
+    size_t req_len = req_fixed_len + tlv_required_space(hash_length);
+
+    *signature_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+
+    struct tlv_record hash_record;
+    hash_record.tag = TS_CRYPTO_SIGN_HASH_IN_TAG_HASH;
+    hash_record.length = hash_length;
+    hash_record.value = hash;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_fixed_len);
+
+        tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+        tlv_encode(&req_iter, &hash_record);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    TS_CRYPTO_OPCODE_SIGN_HASH, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_SIGN_HASH_OUT_TAG_SIGNATURE, &decoded_record)) {
+
+                    if (decoded_record.length <= signature_size) {
+
+                        memcpy(signature, decoded_record.value, decoded_record.length);
+                        *signature_length = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+
+psa_status_t packedc_crypto_client::verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *hash, size_t hash_length,
+                        const uint8_t *signature, size_t signature_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_verify_hash_in req_msg;
+    size_t req_fixed_len = sizeof(ts_crypto_verify_hash_in);
+    size_t req_len = req_fixed_len + tlv_required_space(hash_length) + tlv_required_space(signature_length);
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+
+    struct tlv_record hash_record;
+    hash_record.tag = TS_CRYPTO_VERIFY_HASH_IN_TAG_HASH;
+    hash_record.length = hash_length;
+    hash_record.value = hash;
+
+    struct tlv_record sig_record;
+    sig_record.tag = TS_CRYPTO_VERIFY_HASH_IN_TAG_SIGNATURE;
+    sig_record.length = signature_length;
+    sig_record.value = signature;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_fixed_len);
+
+        tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+        tlv_encode(&req_iter, &hash_record);
+        tlv_encode(&req_iter, &sig_record);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    TS_CRYPTO_OPCODE_VERIFY_HASH, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *input, size_t input_length,
+                        const uint8_t *salt, size_t salt_length,
+                        uint8_t *output, size_t output_size, size_t *output_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_asymmetric_encrypt_in req_msg;
+    size_t req_fixed_len = sizeof(ts_crypto_asymmetric_encrypt_in);
+    size_t req_len = req_fixed_len + tlv_required_space(input_length) + tlv_required_space(salt_length);
+
+    *output_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+
+    struct tlv_record plaintext_record;
+    plaintext_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT;
+    plaintext_record.length = input_length;
+    plaintext_record.value = input;
+
+    struct tlv_record salt_record;
+    salt_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT;
+    salt_record.length = salt_length;
+    salt_record.value = salt;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus = PSA_ERROR_GENERIC_ERROR;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_fixed_len);
+
+        tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+        tlv_encode(&req_iter, &plaintext_record);
+        tlv_encode(&req_iter, &salt_record);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_OUT_TAG_CIPHERTEXT, &decoded_record)) {
+
+                    if (decoded_record.length <= output_size) {
+
+                        memcpy(output, decoded_record.value, decoded_record.length);
+                        *output_length = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *input, size_t input_length,
+                        const uint8_t *salt, size_t salt_length,
+                        uint8_t *output, size_t output_size, size_t *output_length)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_asymmetric_decrypt_in req_msg;
+    size_t req_fixed_len = sizeof(ts_crypto_asymmetric_decrypt_in);
+    size_t req_len = req_fixed_len + tlv_required_space(input_length) + tlv_required_space(salt_length);
+
+    *output_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+
+    struct tlv_record ciphertext_record;
+    ciphertext_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT;
+    ciphertext_record.length = input_length;
+    ciphertext_record.value = input;
+
+    struct tlv_record salt_record;
+    salt_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT;
+    salt_record.length = salt_length;
+    salt_record.value = salt;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+        struct tlv_iterator req_iter;
+
+        memcpy(req_buf, &req_msg, req_fixed_len);
+
+        tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+        tlv_encode(&req_iter, &ciphertext_record);
+        tlv_encode(&req_iter, &salt_record);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_OUT_TAG_PLAINTEXT, &decoded_record)) {
+
+                    if (decoded_record.length <= output_size) {
+
+                        memcpy(output, decoded_record.value, decoded_record.length);
+                        *output_length = decoded_record.length;
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+psa_status_t packedc_crypto_client::generate_random(uint8_t *output, size_t output_size)
+{
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    struct ts_crypto_generate_random_in req_msg;
+    size_t req_len = sizeof(ts_crypto_generate_random_in);
+
+    req_msg.size = output_size;
+
+    rpc_call_handle call_handle;
+    uint8_t *req_buf;
+
+    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+    if (call_handle) {
+
+        uint8_t *resp_buf;
+        size_t resp_len;
+        int opstatus;
+
+        memcpy(req_buf, &req_msg, req_len);
+
+        m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                TS_CRYPTO_OPCODE_GENERATE_RANDOM, &opstatus, &resp_buf, &resp_len);
+
+        if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+            psa_status = opstatus;
+
+            if (psa_status == PSA_SUCCESS) {
+
+                struct tlv_const_iterator resp_iter;
+                struct tlv_record decoded_record;
+                tlv_const_iterator_begin(&resp_iter, resp_buf, resp_len);
+
+                if (tlv_find_decode(&resp_iter, TS_CRYPTO_GENERATE_RANDOM_OUT_TAG_RANDOM_BYTES, &decoded_record)) {
+
+                    if (decoded_record.length <= output_size) {
+
+                        memcpy(output, decoded_record.value, decoded_record.length);
+                    }
+                    else {
+                        /* Provided buffer is too small */
+                        psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                    }
+                }
+                else {
+                    /* Mandatory response parameter missing */
+                    psa_status = PSA_ERROR_GENERIC_ERROR;
+                }
+            }
+        }
+
+        rpc_caller_end(m_caller, call_handle);
+    }
+
+    return psa_status;
+}
+
+void packedc_crypto_client::translate_key_attributes(struct ts_crypto_key_attributes &proto_attributes,
+                            const psa_key_attributes_t &psa_attributes)
+{
+    proto_attributes.type = psa_get_key_type(&psa_attributes);
+    proto_attributes.key_bits = psa_get_key_bits(&psa_attributes);
+    proto_attributes.lifetime = psa_get_key_lifetime(&psa_attributes);
+    proto_attributes.id = psa_get_key_id(&psa_attributes);
+
+    proto_attributes.policy.usage = psa_get_key_usage_flags(&psa_attributes);
+    proto_attributes.policy.alg = psa_get_key_algorithm(&psa_attributes);
+ }
diff --git a/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.h b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.h
new file mode 100644
index 0000000..fb5d772
--- /dev/null
+++ b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_CLIENT_H
+#define PACKEDC_CRYPTO_CLIENT_H
+
+#include <service/crypto/client/cpp/crypto_client.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+
+/*
+ * A concrete crypto_client that uses the packed-c based crypto access protocol
+ */
+class packedc_crypto_client : public crypto_client
+{
+public:
+    packedc_crypto_client();
+    packedc_crypto_client(struct rpc_caller *caller);
+    virtual ~packedc_crypto_client();
+
+    /* Key lifecycle methods */
+    psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle);
+    psa_status_t destroy_key(psa_key_handle_t handle);
+    psa_status_t open_key(psa_key_id_t id, psa_key_handle_t *handle);
+    psa_status_t close_key(psa_key_handle_t handle);
+    psa_status_t import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data, size_t data_length, psa_key_handle_t *handle);
+
+    /* Key export methods */
+    psa_status_t export_key(psa_key_handle_t handle,
+                            uint8_t *data, size_t data_size,
+                            size_t *data_length);
+    psa_status_t export_public_key(psa_key_handle_t handle,
+                            uint8_t *data, size_t data_size, size_t *data_length);
+
+    /* Sign/verify methods */
+    psa_status_t sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            uint8_t *signature, size_t signature_size, size_t *signature_length);
+    psa_status_t verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            const uint8_t *signature, size_t signature_length);
+
+    /* Asymmetric encrypt/decrypt */
+    psa_status_t asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *input, size_t input_length,
+                            const uint8_t *salt, size_t salt_length,
+                            uint8_t *output, size_t output_size, size_t *output_length);
+    psa_status_t asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *input, size_t input_length,
+                            const uint8_t *salt, size_t salt_length,
+                            uint8_t *output, size_t output_size, size_t *output_length);
+
+    /* Random number generation */
+    psa_status_t generate_random(uint8_t *output, size_t output_size);
+
+private:
+
+    void translate_key_attributes(struct ts_crypto_key_attributes &proto_attributes,
+                            const psa_key_attributes_t &psa_attributes);
+};
+
+#endif /* PACKEDC_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/cpp/protobuf/component.cmake b/components/service/crypto/client/cpp/protobuf/component.cmake
new file mode 100644
index 0000000..ddb3f6b
--- /dev/null
+++ b/components/service/crypto/client/cpp/protobuf/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/protobuf_crypto_client.cpp"
+	)
+
diff --git a/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp
new file mode 100644
index 0000000..6818590
--- /dev/null
+++ b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp
@@ -0,0 +1,799 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include <cstdlib>
+#include "protobuf_crypto_client.h"
+#include <protocols/rpc/common/packed-c/status.h>
+#include <service/common/serializer/protobuf/pb_helper.h>
+#include <rpc_caller.h>
+#include <service/crypto/protobuf/opcodes.pb.h>
+#include <service/crypto/protobuf/generate_key.pb.h>
+#include <service/crypto/protobuf/destroy_key.pb.h>
+#include <service/crypto/protobuf/import_key.pb.h>
+#include <service/crypto/protobuf/open_key.pb.h>
+#include <service/crypto/protobuf/close_key.pb.h>
+#include <service/crypto/protobuf/export_key.pb.h>
+#include <service/crypto/protobuf/export_public_key.pb.h>
+#include <service/crypto/protobuf/sign_hash.pb.h>
+#include <service/crypto/protobuf/verify_hash.pb.h>
+#include <service/crypto/protobuf/asymmetric_encrypt.pb.h>
+#include <service/crypto/protobuf/asymmetric_decrypt.pb.h>
+#include <service/crypto/protobuf/generate_random.pb.h>
+#include <pb_encode.h>
+#include <pb_decode.h>
+
+protobuf_crypto_client::protobuf_crypto_client() :
+    crypto_client()
+{
+
+}
+
+protobuf_crypto_client::protobuf_crypto_client(struct rpc_caller *caller) :
+    crypto_client(caller)
+{
+
+}
+
+protobuf_crypto_client::~protobuf_crypto_client()
+{
+
+}
+
+psa_status_t protobuf_crypto_client::generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_GenerateKeyIn req_msg = ts_crypto_GenerateKeyIn_init_default;
+
+    translate_key_attributes(req_msg.attributes, *attributes);
+    req_msg.has_attributes = true;
+
+    if (pb_get_encoded_size(&req_len, ts_crypto_GenerateKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_GenerateKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_GENERATE_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    ts_crypto_GenerateKeyOut resp_msg = ts_crypto_GenerateKeyOut_init_default;
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_GenerateKeyOut_fields, &resp_msg)) {
+
+                        *handle = resp_msg.handle;
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::destroy_key(psa_key_handle_t handle)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_DestroyKeyIn req_msg = ts_crypto_DestroyKeyIn_init_default;
+
+    req_msg.handle = handle;
+
+    if (pb_get_encoded_size(&req_len, ts_crypto_DestroyKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_DestroyKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_DESTROY_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::open_key(psa_key_id_t id, psa_key_handle_t *handle)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_OpenKeyIn req_msg = ts_crypto_OpenKeyIn_init_default;
+    req_msg.id = id;
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_OpenKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_OpenKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                        ts_crypto_Opcode_OPEN_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    ts_crypto_OpenKeyOut resp_msg = ts_crypto_OpenKeyOut_init_default;
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_OpenKeyOut_fields, &resp_msg)) {
+
+                        *handle = resp_msg.handle;
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::close_key(psa_key_handle_t handle)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_CloseKeyIn req_msg = ts_crypto_CloseKeyIn_init_default;
+
+    req_msg.handle = handle;
+
+    if (pb_get_encoded_size(&req_len, ts_crypto_CloseKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_CloseKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_CLOSE_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::import_key(const psa_key_attributes_t *attributes,
+                        const uint8_t *data, size_t data_length, psa_key_handle_t *handle)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_ImportKeyIn req_msg = ts_crypto_ImportKeyIn_init_default;
+    pb_bytes_array_t *key_byte_array = pb_malloc_byte_array_containing_bytes(data, data_length);
+
+    translate_key_attributes(req_msg.attributes, *attributes);
+    req_msg.has_attributes = true;
+    req_msg.data = pb_out_byte_array(key_byte_array);
+
+    if (pb_get_encoded_size(&req_len, ts_crypto_ImportKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_ImportKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_IMPORT_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    ts_crypto_ImportKeyOut resp_msg = ts_crypto_ImportKeyOut_init_default;
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_ImportKeyOut_fields, &resp_msg)) {
+
+                        *handle = resp_msg.handle;
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    ::free(key_byte_array);
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::export_key(psa_key_handle_t handle,
+                        uint8_t *data, size_t data_size,
+                        size_t *data_length)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_ExportKeyIn req_msg = ts_crypto_ExportKeyIn_init_default;
+    req_msg.handle = handle;
+
+    *data_length = 0; /* For failure case */
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_ExportKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_ExportKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_EXPORT_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    ts_crypto_ExportKeyOut resp_msg = ts_crypto_ExportKeyOut_init_default;
+                    pb_bytes_array_t *exported_key = pb_malloc_byte_array(resp_len);
+
+                    if (exported_key) {
+
+                        resp_msg.data = pb_in_byte_array(exported_key);
+                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                        if (pb_decode(&istream, ts_crypto_ExportKeyOut_fields, &resp_msg)) {
+
+                            if (exported_key->size <= data_size) {
+
+                                memcpy(data, exported_key->bytes, exported_key->size);
+                                *data_length = exported_key->size;
+                            }
+                            else {
+                                /* Provided buffer is too small */
+                                psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                            }
+                        }
+                        else {
+                            /* Failed to decode response message */
+                            psa_status = PSA_ERROR_GENERIC_ERROR;
+                        }
+
+                        ::free(exported_key);
+                    }
+                    else {
+                        /* Failed to allocate buffer for exported key */
+                        psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
+                    }
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::export_public_key(psa_key_handle_t handle,
+                                uint8_t *data, size_t data_size, size_t *data_length)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_ExportPublicKeyIn req_msg = ts_crypto_ExportPublicKeyIn_init_default;
+    req_msg.handle = handle;
+
+    *data_length = 0; /* For failure case */
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_ExportPublicKeyIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_ExportPublicKeyIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                ts_crypto_Opcode_EXPORT_PUBLIC_KEY, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    ts_crypto_ExportPublicKeyOut resp_msg = ts_crypto_ExportPublicKeyOut_init_default;
+                    pb_bytes_array_t *exported_key = pb_malloc_byte_array(resp_len);
+
+                    if (exported_key) {
+
+                        resp_msg.data = pb_in_byte_array(exported_key);
+                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                        if (pb_decode(&istream, ts_crypto_ExportPublicKeyOut_fields, &resp_msg)) {
+
+                            if (exported_key->size <= data_size) {
+
+                                memcpy(data, exported_key->bytes, exported_key->size);
+                                *data_length = exported_key->size;
+                            }
+                            else {
+                                /* Provided buffer is too small */
+                                psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                            }
+                        }
+                        else {
+                            /* Failed to decode response message */
+                            psa_status = PSA_ERROR_GENERIC_ERROR;
+                        }
+
+                        ::free(exported_key);
+                    }
+                    else {
+                        /* Failed to alloocate buffer for exported key */
+                        psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
+                    }
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            uint8_t *signature, size_t signature_size, size_t *signature_length)
+{
+    size_t req_len;
+    pb_bytes_array_t *hash_byte_array = pb_malloc_byte_array_containing_bytes(hash, hash_length);
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_SignHashIn req_msg = ts_crypto_SignHashIn_init_default;
+
+    *signature_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+	req_msg.hash = pb_out_byte_array(hash_byte_array);
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_SignHashIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_SignHashIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                        ts_crypto_Opcode_SIGN_HASH, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    pb_bytes_array_t *sig_byte_array = pb_malloc_byte_array(PSA_SIGNATURE_MAX_SIZE);
+                    ts_crypto_SignHashOut resp_msg = ts_crypto_SignHashOut_init_default;
+                    resp_msg.signature = pb_in_byte_array(sig_byte_array);
+
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_SignHashOut_fields, &resp_msg)) {
+
+                        if (sig_byte_array->size <= signature_size) {
+
+                            memcpy(signature, sig_byte_array->bytes, sig_byte_array->size);
+                            *signature_length = sig_byte_array->size;
+                        }
+                        else {
+                            /* Provided buffer is too small */
+                            psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                        }
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+
+                    ::free(sig_byte_array);
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    ::free(hash_byte_array);
+
+    return psa_status;
+}
+
+
+psa_status_t protobuf_crypto_client::verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *hash, size_t hash_length,
+                        const uint8_t *signature, size_t signature_length)
+{
+    size_t req_len;
+    pb_bytes_array_t *hash_byte_array = pb_malloc_byte_array_containing_bytes(hash, hash_length);
+    pb_bytes_array_t *sig_byte_array = pb_malloc_byte_array_containing_bytes(signature, signature_length);
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_VerifyHashIn req_msg = ts_crypto_VerifyHashIn_init_default;
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+	req_msg.hash = pb_out_byte_array(hash_byte_array);
+    req_msg.signature = pb_out_byte_array(sig_byte_array);
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_VerifyHashIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_VerifyHashIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                        ts_crypto_Opcode_VERIFY_HASH, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    ::free(hash_byte_array);
+    ::free(sig_byte_array);
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *input, size_t input_length,
+                        const uint8_t *salt, size_t salt_length,
+                        uint8_t *output, size_t output_size, size_t *output_length)
+{
+    size_t req_len;
+    pb_bytes_array_t *plaintext_byte_array = pb_malloc_byte_array_containing_bytes(input, input_length);
+    pb_bytes_array_t *salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_AsymmetricEncryptIn req_msg = ts_crypto_AsymmetricEncryptIn_init_default;
+
+    *output_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+	req_msg.plaintext = pb_out_byte_array(plaintext_byte_array);
+    req_msg.salt = pb_out_byte_array(salt_byte_array);
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricEncryptIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus = PSA_ERROR_GENERIC_ERROR;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_AsymmetricEncryptIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                        ts_crypto_Opcode_ASYMMETRIC_ENCRYPT, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    pb_bytes_array_t *ciphertext_byte_array = pb_malloc_byte_array(output_size);
+                    ts_crypto_AsymmetricEncryptOut resp_msg = ts_crypto_AsymmetricEncryptOut_init_default;
+                    resp_msg.ciphertext = pb_in_byte_array(ciphertext_byte_array);
+
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
+
+                        if (ciphertext_byte_array->size <= output_size) {
+
+                            memcpy(output, ciphertext_byte_array->bytes, ciphertext_byte_array->size);
+                            *output_length = ciphertext_byte_array->size;
+                        }
+                        else {
+                            /* Provided buffer is too small */
+                            psa_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                        }
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+
+                    ::free(ciphertext_byte_array);
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    ::free(plaintext_byte_array);
+    ::free(salt_byte_array);
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                        const uint8_t *input, size_t input_length,
+                        const uint8_t *salt, size_t salt_length,
+                        uint8_t *output, size_t output_size, size_t *output_length)
+{
+    size_t req_len;
+    pb_bytes_array_t *ciphertext_byte_array = pb_malloc_byte_array_containing_bytes(input, input_length);
+    pb_bytes_array_t *salt_byte_array = pb_malloc_byte_array_containing_bytes(salt, salt_length);
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_AsymmetricDecryptIn req_msg = ts_crypto_AsymmetricDecryptIn_init_default;
+
+    *output_length = 0;  /* For failure case */
+
+    req_msg.handle = handle;
+    req_msg.alg = alg;
+	req_msg.ciphertext = pb_out_byte_array(ciphertext_byte_array);
+    req_msg.salt = pb_out_byte_array(salt_byte_array);
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_AsymmetricDecryptIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_AsymmetricDecryptIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                        ts_crypto_Opcode_ASYMMETRIC_DECRYPT, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    pb_bytes_array_t *plaintext_byte_array = pb_malloc_byte_array(output_size);
+                    ts_crypto_AsymmetricDecryptOut resp_msg = ts_crypto_AsymmetricDecryptOut_init_default;
+                    resp_msg.plaintext = pb_in_byte_array(plaintext_byte_array);
+
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
+
+                        if (plaintext_byte_array->size <= output_size) {
+
+                            memcpy(output, plaintext_byte_array->bytes, plaintext_byte_array->size);
+                            *output_length = plaintext_byte_array->size;
+                        }
+                        else {
+                            /* Provided buffer is too small */
+                            m_err_rpc_status = PSA_ERROR_BUFFER_TOO_SMALL;
+                        }
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        m_err_rpc_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+
+                    ::free(plaintext_byte_array);
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    ::free(ciphertext_byte_array);
+    ::free(salt_byte_array);
+
+    return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::generate_random(uint8_t *output, size_t output_size)
+{
+    size_t req_len;
+    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+    ts_crypto_GenerateRandomIn req_msg = ts_crypto_GenerateRandomIn_init_default;
+
+    req_msg.size = output_size;
+
+	if (pb_get_encoded_size(&req_len, ts_crypto_GenerateRandomIn_fields, &req_msg)) {
+
+        rpc_call_handle call_handle;
+        uint8_t *req_buf;
+
+        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+
+        if (call_handle) {
+
+            uint8_t *resp_buf;
+            size_t resp_len;
+            int opstatus;
+
+            pb_ostream_t ostream = pb_ostream_from_buffer(req_buf, req_len);
+            pb_encode(&ostream, ts_crypto_GenerateRandomIn_fields, &req_msg);
+
+            m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+                    ts_crypto_Opcode_GENERATE_RANDOM, &opstatus, &resp_buf, &resp_len);
+
+            if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+                psa_status = opstatus;
+
+                if (psa_status == PSA_SUCCESS) {
+
+                    pb_bytes_array_t *output_byte_array = pb_malloc_byte_array(output_size);
+                    ts_crypto_GenerateRandomOut resp_msg = ts_crypto_GenerateRandomOut_init_default;
+                    resp_msg.random_bytes = pb_in_byte_array(output_byte_array);
+
+                    pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+
+                    if (pb_decode(&istream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
+
+                        if (output_byte_array->size == output_size) {
+
+                            memcpy(output, output_byte_array->bytes, output_byte_array->size);
+                        }
+                        else {
+                            /* Mismatch between requested and generated length */
+                            psa_status = PSA_ERROR_GENERIC_ERROR;
+                        }
+                    }
+                    else {
+                        /* Failed to decode response message */
+                        psa_status = PSA_ERROR_GENERIC_ERROR;
+                    }
+
+                    ::free(output_byte_array);
+                }
+            }
+
+            rpc_caller_end(m_caller, call_handle);
+        }
+    }
+
+    return psa_status;
+}
+
+void protobuf_crypto_client::translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
+                            const psa_key_attributes_t &psa_attributes)
+{
+    proto_attributes.type = psa_get_key_type(&psa_attributes);
+    proto_attributes.key_bits = psa_get_key_bits(&psa_attributes);
+    proto_attributes.lifetime = psa_get_key_lifetime(&psa_attributes);
+    proto_attributes.id = psa_get_key_id(&psa_attributes);
+
+    proto_attributes.has_policy = true;
+    proto_attributes.policy.usage = psa_get_key_usage_flags(&psa_attributes);
+    proto_attributes.policy.alg = psa_get_key_algorithm(&psa_attributes);
+ }
diff --git a/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.h b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.h
new file mode 100644
index 0000000..e2a355a
--- /dev/null
+++ b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PROTOBUF_CRYPTO_CLIENT_H
+#define PROTOBUF_CRYPTO_CLIENT_H
+
+#include <service/crypto/client/cpp/crypto_client.h>
+#include <service/crypto/protobuf/key_attributes.pb.h>
+
+/*
+ * A concrete crypto_client that uses the protobuf based crypto access protocol
+ */
+class protobuf_crypto_client : public crypto_client
+{
+public:
+    protobuf_crypto_client();
+    protobuf_crypto_client(struct rpc_caller *caller);
+    virtual ~protobuf_crypto_client();
+
+    /* Key lifecycle methods */
+    psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_handle_t *handle);
+    psa_status_t destroy_key(psa_key_handle_t handle);
+    psa_status_t open_key(psa_key_id_t id, psa_key_handle_t *handle);
+    psa_status_t close_key(psa_key_handle_t handle);
+    psa_status_t import_key(const psa_key_attributes_t *attributes,
+                            const uint8_t *data, size_t data_length, psa_key_handle_t *handle);
+
+    /* Key export methods */
+    psa_status_t export_key(psa_key_handle_t handle,
+                            uint8_t *data, size_t data_size,
+                            size_t *data_length);
+    psa_status_t export_public_key(psa_key_handle_t handle,
+                            uint8_t *data, size_t data_size, size_t *data_length);
+
+    /* Sign/verify methods */
+    psa_status_t sign_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            uint8_t *signature, size_t signature_size, size_t *signature_length);
+    psa_status_t verify_hash(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *hash, size_t hash_length,
+                            const uint8_t *signature, size_t signature_length);
+
+    /* Asymmetric encrypt/decrypt */
+    psa_status_t asymmetric_encrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *input, size_t input_length,
+                            const uint8_t *salt, size_t salt_length,
+                            uint8_t *output, size_t output_size, size_t *output_length);
+    psa_status_t asymmetric_decrypt(psa_key_handle_t handle, psa_algorithm_t alg,
+                            const uint8_t *input, size_t input_length,
+                            const uint8_t *salt, size_t salt_length,
+                            uint8_t *output, size_t output_size, size_t *output_length);
+
+    /* Random number generation */
+    psa_status_t generate_random(uint8_t *output, size_t output_size);
+
+private:
+
+    void translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
+                            const psa_key_attributes_t &psa_attributes);
+};
+
+#endif /* PROTOBUF_CRYPTO_CLIENT_H */
diff --git a/components/service/crypto/client/test/mock/mock_crypto_client.cpp b/components/service/crypto/client/test/mock/mock_crypto_client.cpp
index a654ed1..4ca482a 100644
--- a/components/service/crypto/client/test/mock/mock_crypto_client.cpp
+++ b/components/service/crypto/client/test/mock/mock_crypto_client.cpp
@@ -6,6 +6,7 @@
 
 #include "mock_crypto_client.h"
 #include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
+#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
 
 mock_crypto_client::mock_crypto_client() :
     test_crypto_client(),
@@ -40,6 +41,9 @@
         mbed_crypto_provider_register_serializer(&m_crypto_provider,
                     TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
 
+        mbed_crypto_provider_register_serializer(&m_crypto_provider,
+                    TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+
         rpc_caller_set_encoding_scheme(crypto_caller, TS_RPC_ENCODING_PROTOBUF);
 
         crypto_client::set_caller(crypto_caller);
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
index 459e42d..343bec1 100644
--- a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
@@ -8,6 +8,7 @@
 #include <protocols/rpc/common/packed-c/status.h>
 #include <protocols/service/psa/packed-c/status.h>
 #include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
+#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
 
 standalone_crypto_client::standalone_crypto_client() :
     test_crypto_client(),
@@ -58,6 +59,9 @@
         mbed_crypto_provider_register_serializer(&m_crypto_provider,
                     TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
 
+        mbed_crypto_provider_register_serializer(&m_crypto_provider,
+                    TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+
         rpc_caller_set_encoding_scheme(crypto_caller, TS_RPC_ENCODING_PROTOBUF);
 
         crypto_client::set_caller(crypto_caller);
diff --git a/components/service/crypto/client/test/test_crypto_client.cpp b/components/service/crypto/client/test/test_crypto_client.cpp
index 7232790..3217c61 100644
--- a/components/service/crypto/client/test/test_crypto_client.cpp
+++ b/components/service/crypto/client/test/test_crypto_client.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,7 +10,7 @@
 test_crypto_client::factory *test_crypto_client::m_default_factory = NULL;
 
 test_crypto_client::test_crypto_client() :
-    crypto_client(),
+    protobuf_crypto_client(),
     m_is_initialized(false),
     m_injected_faults()
 {
diff --git a/components/service/crypto/client/test/test_crypto_client.h b/components/service/crypto/client/test/test_crypto_client.h
index 5b927db..f1d70a1 100644
--- a/components/service/crypto/client/test/test_crypto_client.h
+++ b/components/service/crypto/client/test/test_crypto_client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,7 +7,7 @@
 #ifndef TEST_CRYPTO_CLIENT_H
 #define TEST_CRYPTO_CLIENT_H
 
-#include <service/crypto/client/cpp/crypto_client.h>
+#include <service/crypto/client/cpp/protobuf/protobuf_crypto_client.h>
 #include <vector>
 
 /*
@@ -20,7 +20,7 @@
  * Each virtual test method is paired with a is_supported() method to
  * allow test cases to adapt to circumstances.
  */
-class test_crypto_client : public crypto_client
+class test_crypto_client : public protobuf_crypto_client
 {
 public:
     virtual ~test_crypto_client();
diff --git a/components/service/crypto/provider/serializer/packed-c/component.cmake b/components/service/crypto/provider/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..f4b0106
--- /dev/null
+++ b/components/service/crypto/provider/serializer/packed-c/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/packedc_crypto_provider_serializer.c"
+	"${CMAKE_CURRENT_LIST_DIR}/packedc_key_attributes_translator.c"
+	)
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
new file mode 100644
index 0000000..f39aa1c
--- /dev/null
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <common/tlv/tlv.h>
+#include <psa/crypto.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <protocols/service/crypto/packed-c/asymmetric_decrypt.h>
+#include <protocols/service/crypto/packed-c/asymmetric_encrypt.h>
+#include <protocols/service/crypto/packed-c/close_key.h>
+#include <protocols/service/crypto/packed-c/destroy_key.h>
+#include <protocols/service/crypto/packed-c/export_key.h>
+#include <protocols/service/crypto/packed-c/export_public_key.h>
+#include <protocols/service/crypto/packed-c/generate_key.h>
+#include <protocols/service/crypto/packed-c/generate_random.h>
+#include <protocols/service/crypto/packed-c/import_key.h>
+#include <protocols/service/crypto/packed-c/open_key.h>
+#include <protocols/service/crypto/packed-c/sign_hash.h>
+#include <protocols/service/crypto/packed-c/verify_hash.h>
+#include "packedc_crypto_provider_serializer.h"
+#include "packedc_key_attributes_translator.h"
+
+/* Returns the maximum possible deserialized parameter size for a packed-c encoded message. */
+static size_t max_deserialised_parameter_size(const struct call_param_buf *req_buf)
+{
+    /*
+     * Assume that a deserialized parameter must be the same size or smaller than the
+     * entire serialized message.
+     */
+    return req_buf->data_len;
+}
+
+/* Operation: generate_key */
+static rpc_status_t deserialize_generate_key_req(const struct call_param_buf *req_buf,
+                                            psa_key_attributes_t *attributes)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_generate_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_generate_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        packedc_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_generate_key_resp(struct call_param_buf *resp_buf,
+                                            psa_key_handle_t handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct ts_crypto_generate_key_out resp_msg;
+    size_t fixed_len = sizeof(struct ts_crypto_generate_key_out);
+
+    resp_msg.handle = handle;
+
+    if (fixed_len <= resp_buf->size) {
+
+        memcpy(resp_buf->data, &resp_msg, fixed_len);
+        resp_buf->data_len = fixed_len;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: destroy_key */
+static rpc_status_t deserialize_destroy_key_req(const struct call_param_buf *req_buf,
+                                            psa_key_handle_t *handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_destroy_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_destroy_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *handle = recv_msg.handle;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: open_key */
+static rpc_status_t deserialize_open_key_req(const struct call_param_buf *req_buf, psa_key_id_t *id)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_open_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_open_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *id = recv_msg.id;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_open_key_resp(struct call_param_buf *resp_buf,
+                                psa_key_handle_t handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct ts_crypto_open_key_out resp_msg;
+    size_t fixed_len = sizeof(struct ts_crypto_open_key_out);
+
+    resp_msg.handle = handle;
+
+    if (fixed_len <= resp_buf->size) {
+
+        memcpy(resp_buf->data, &resp_msg, fixed_len);
+        resp_buf->data_len = fixed_len;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: close_key */
+static rpc_status_t deserialize_close_key_req(const struct call_param_buf *req_buf,
+                                psa_key_handle_t *handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_close_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_close_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *handle = recv_msg.handle;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: export_key */
+static rpc_status_t deserialize_export_key_req(const struct call_param_buf *req_buf,
+                                            psa_key_handle_t *handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_export_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_export_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *handle = recv_msg.handle;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_export_key_resp(struct call_param_buf *resp_buf,
+                                    const uint8_t *data, size_t data_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record key_record;
+    key_record.tag = TS_CRYPTO_EXPORT_KEY_OUT_TAG_DATA;
+    key_record.length = data_len;
+    key_record.value = data;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &key_record)) {
+
+        resp_buf->data_len = tlv_required_space(data_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: export_public_key */
+static rpc_status_t deserialize_export_public_key_req(const struct call_param_buf *req_buf,
+                                                psa_key_handle_t *handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_export_public_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_export_public_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *handle = recv_msg.handle;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_export_public_key_resp(struct call_param_buf *resp_buf,
+                                            const uint8_t *data, size_t data_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record key_record;
+    key_record.tag = TS_CRYPTO_EXPORT_PUBLIC_KEY_OUT_TAG_DATA;
+    key_record.length = data_len;
+    key_record.value = data;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &key_record)) {
+
+        resp_buf->data_len = tlv_required_space(data_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: import_key */
+static rpc_status_t deserialize_import_key_req(const struct call_param_buf *req_buf,
+                    psa_key_attributes_t *attributes, uint8_t *data, size_t *data_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_import_key_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_import_key_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator resp_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        packedc_crypto_provider_translate_key_attributes(attributes, &recv_msg.attributes);
+
+        tlv_const_iterator_begin(&resp_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_IMPORT_KEY_IN_TAG_DATA, &decoded_record)) {
+
+            if (decoded_record.length <= *data_len) {
+
+                memcpy(data, decoded_record.value, decoded_record.length);
+                *data_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default for missing parameter */
+            *data_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_import_key_resp(struct call_param_buf *resp_buf,
+                                        psa_key_handle_t handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct ts_crypto_import_key_out resp_msg;
+    size_t fixed_len = sizeof(struct ts_crypto_import_key_out);
+
+    resp_msg.handle = handle;
+
+    if (fixed_len <= resp_buf->size) {
+
+        memcpy(resp_buf->data, &resp_msg, fixed_len);
+        resp_buf->data_len = fixed_len;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: sign_hash */
+static rpc_status_t deserialize_sign_hash_req(const struct call_param_buf *req_buf,
+                            psa_key_handle_t *handle, psa_algorithm_t *alg,
+                            uint8_t *hash, size_t *hash_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_sign_hash_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_sign_hash_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator resp_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+        *handle = recv_msg.handle;
+        *alg = recv_msg.alg;
+
+        tlv_const_iterator_begin(&resp_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_SIGN_HASH_IN_TAG_HASH, &decoded_record)) {
+
+            if (decoded_record.length <= *hash_len) {
+
+                memcpy(hash, decoded_record.value, decoded_record.length);
+                *hash_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *hash_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_sign_hash_resp(struct call_param_buf *resp_buf,
+                            const uint8_t *sig, size_t sig_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record sig_record;
+    sig_record.tag = TS_CRYPTO_SIGN_HASH_OUT_TAG_SIGNATURE;
+    sig_record.length = sig_len;
+    sig_record.value = sig;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &sig_record)) {
+
+        resp_buf->data_len = tlv_required_space(sig_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: verify_hash */
+static rpc_status_t deserialize_verify_hash_req(const struct call_param_buf *req_buf,
+                                psa_key_handle_t *handle, psa_algorithm_t *alg,
+                                uint8_t *hash, size_t *hash_len,
+                                uint8_t *sig, size_t *sig_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_verify_hash_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_verify_hash_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator resp_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+        *handle = recv_msg.handle;
+        *alg = recv_msg.alg;
+
+        tlv_const_iterator_begin(&resp_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_HASH, &decoded_record)) {
+
+            if (decoded_record.length <= *hash_len) {
+
+                memcpy(hash, decoded_record.value, decoded_record.length);
+                *hash_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *hash_len = 0;
+        }
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_VERIFY_HASH_IN_TAG_SIGNATURE, &decoded_record)) {
+
+            if (decoded_record.length <= *sig_len) {
+
+                memcpy(sig, decoded_record.value, decoded_record.length);
+                *sig_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *sig_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+/* Operation: asymmetric_decrypt */
+static rpc_status_t deserialize_asymmetric_decrypt_req(const struct call_param_buf *req_buf,
+                                psa_key_handle_t *handle, psa_algorithm_t *alg,
+                                uint8_t *ciphertext, size_t *ciphertext_len,
+                                uint8_t *salt, size_t *salt_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_asymmetric_decrypt_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_decrypt_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator resp_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+        *handle = recv_msg.handle;
+        *alg = recv_msg.alg;
+
+        tlv_const_iterator_begin(&resp_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT, &decoded_record)) {
+
+            if (decoded_record.length <= *ciphertext_len) {
+
+                memcpy(ciphertext, decoded_record.value, decoded_record.length);
+                *ciphertext_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *ciphertext_len = 0;
+        }
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT, &decoded_record)) {
+
+            if (decoded_record.length <= *salt_len) {
+
+                memcpy(salt, decoded_record.value, decoded_record.length);
+                *salt_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *salt_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_asymmetric_decrypt_resp(struct call_param_buf *resp_buf,
+                                const uint8_t *plaintext, size_t plaintext_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record sig_record;
+    sig_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_OUT_TAG_PLAINTEXT;
+    sig_record.length = plaintext_len;
+    sig_record.value = plaintext;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &sig_record)) {
+
+        resp_buf->data_len = tlv_required_space(plaintext_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: asymmetric_encrypt */
+static rpc_status_t deserialize_asymmetric_encrypt_req(const struct call_param_buf *req_buf,
+                                    psa_key_handle_t *handle, psa_algorithm_t *alg,
+                                    uint8_t *plaintext, size_t *plaintext_len,
+                                    uint8_t *salt, size_t *salt_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_asymmetric_encrypt_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_asymmetric_encrypt_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator resp_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+        *handle = recv_msg.handle;
+        *alg = recv_msg.alg;
+
+        tlv_const_iterator_begin(&resp_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT, &decoded_record)) {
+
+            if (decoded_record.length <= *plaintext_len) {
+
+                memcpy(plaintext, decoded_record.value, decoded_record.length);
+                *plaintext_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *plaintext_len = 0;
+        }
+
+        if (tlv_find_decode(&resp_iter, TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT, &decoded_record)) {
+
+            if (decoded_record.length <= *salt_len) {
+
+                memcpy(salt, decoded_record.value, decoded_record.length);
+                *salt_len = decoded_record.length;
+            }
+            else {
+                /* Buffer provided too small */
+                return TS_RPC_ERROR_INVALID_REQ_BODY;
+            }
+        }
+        else {
+            /* Default to a zero length hash */
+            *salt_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_asymmetric_encrypt_resp(struct call_param_buf *resp_buf,
+                                    const uint8_t *ciphertext, size_t ciphertext_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record sig_record;
+    sig_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_OUT_TAG_CIPHERTEXT;
+    sig_record.length = ciphertext_len;
+    sig_record.value = ciphertext;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &sig_record)) {
+
+        resp_buf->data_len = tlv_required_space(ciphertext_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Operation: generate_random */
+static rpc_status_t deserialize_generate_random_req(const struct call_param_buf *req_buf,
+                                        size_t *size)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_generate_random_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_generate_random_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *size = recv_msg.size;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_generate_random_resp(struct call_param_buf *resp_buf,
+                                        const uint8_t *output, size_t output_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct tlv_iterator resp_iter;
+
+    struct tlv_record out_record;
+    out_record.tag = TS_CRYPTO_GENERATE_RANDOM_OUT_TAG_RANDOM_BYTES;
+    out_record.length = output_len;
+    out_record.value = output;
+
+    tlv_iterator_begin(&resp_iter, resp_buf->data, resp_buf->size);
+
+    if (tlv_encode(&resp_iter, &out_record)) {
+
+        resp_buf->data_len = tlv_required_space(output_len);
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+/* Singleton method to provide access to the serializer instance */
+const struct crypto_provider_serializer *packedc_crypto_provider_serializer_instance(void)
+{
+    static const struct crypto_provider_serializer instance = {
+        max_deserialised_parameter_size,
+        deserialize_generate_key_req,
+        serialize_generate_key_resp,
+        deserialize_destroy_key_req,
+        deserialize_open_key_req,
+        serialize_open_key_resp,
+        deserialize_close_key_req,
+        deserialize_export_key_req,
+        serialize_export_key_resp,
+        deserialize_export_public_key_req,
+        serialize_export_public_key_resp,
+        deserialize_import_key_req,
+        serialize_import_key_resp,
+        deserialize_sign_hash_req,
+        serialize_sign_hash_resp,
+        deserialize_verify_hash_req,
+        deserialize_asymmetric_decrypt_req,
+        serialize_asymmetric_decrypt_resp,
+        deserialize_asymmetric_encrypt_req,
+        serialize_asymmetric_encrypt_resp,
+        deserialize_generate_random_req,
+        serialize_generate_random_resp
+    };
+
+    return &instance;
+}
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h
new file mode 100644
index 0000000..2fdac43
--- /dev/null
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_PROVIDER_SERIALIZER_H
+#define PACKEDC_CRYPTO_PROVIDER_SERIALIZER_H
+
+#include <service/crypto/provider/serializer/crypto_provider_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the crypto service provider.
+ */
+const struct crypto_provider_serializer *packedc_crypto_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_CRYPTO_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.c b/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.c
new file mode 100644
index 0000000..cb88cec
--- /dev/null
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "packedc_key_attributes_translator.h"
+
+void packedc_crypto_provider_translate_key_attributes(psa_key_attributes_t *psa_attributes,
+    const struct ts_crypto_key_attributes *proto_attributes) {
+
+    psa_set_key_type(psa_attributes, proto_attributes->type);
+    psa_set_key_bits(psa_attributes, proto_attributes->key_bits);
+    psa_set_key_lifetime(psa_attributes, proto_attributes->lifetime);
+
+    if (proto_attributes->lifetime == PSA_KEY_LIFETIME_PERSISTENT) {
+
+        psa_set_key_id(psa_attributes, proto_attributes->id);
+    }
+
+    psa_set_key_usage_flags(psa_attributes, proto_attributes->policy.usage);
+    psa_set_key_algorithm(psa_attributes, proto_attributes->policy.alg);
+}
diff --git a/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.h b/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.h
new file mode 100644
index 0000000..ae8871d
--- /dev/null
+++ b/components/service/crypto/provider/serializer/packed-c/packedc_key_attributes_translator.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_CRYPTO_PROVIDER_KEY_ATTRIBUTES_TRANSLATOR_H
+#define PACKEDC_CRYPTO_PROVIDER_KEY_ATTRIBUTES_TRANSLATOR_H
+
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <psa/crypto.h>
+
+void packedc_crypto_provider_translate_key_attributes(
+    psa_key_attributes_t *psa_attributes,
+    const struct ts_crypto_key_attributes *proto_attributes);
+
+#endif /* PACKEDC_CRYPTO_PROVIDER_KEY_ATTRIBUTES_TRANSLATOR_H */
\ No newline at end of file
diff --git a/components/service/crypto/provider/serializer/protobuf/component.cmake b/components/service/crypto/provider/serializer/protobuf/component.cmake
index 2a075b7..f2772bd 100644
--- a/components/service/crypto/provider/serializer/protobuf/component.cmake
+++ b/components/service/crypto/provider/serializer/protobuf/component.cmake
@@ -12,9 +12,3 @@
 	"${CMAKE_CURRENT_LIST_DIR}/pb_crypto_provider_serializer.c"
 	"${CMAKE_CURRENT_LIST_DIR}/pb_key_attributes_translator.c"
 	)
-
-
-target_include_directories(${TGT}
-	 PRIVATE
-		"${CMAKE_CURRENT_LIST_DIR}"
-	)
diff --git a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
index 2cf38fe..a2631ea 100644
--- a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
+++ b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.c
@@ -29,7 +29,7 @@
 static size_t max_deserialised_parameter_size(const struct call_param_buf *req_buf)
 {
     /*
-     * Assume that a deserialized parameter must be the same size or smalled than the
+     * Assume that a deserialized parameter must be the same size or smaller than the
      * entire serialized message.
      */
     return req_buf->data_len;
diff --git a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h
index 64191c0..08ca2f0 100644
--- a/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h
@@ -13,10 +13,11 @@
 extern "C" {
 #endif
 
-/* Singleton method to provide access to the Protobuf serializer
+/*
+ * Singleton method to provide access to the Protobuf serializer
  * for the crypto service provider.
  */
-extern const struct crypto_provider_serializer *pb_crypto_provider_serializer_instance(void);
+const struct crypto_provider_serializer *pb_crypto_provider_serializer_instance(void);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/components/service/crypto/provider/serializer/protobuf/pb_key_attributes_translator.h b/components/service/crypto/provider/serializer/protobuf/pb_key_attributes_translator.h
index 5de359b..ef77c73 100644
--- a/components/service/crypto/provider/serializer/protobuf/pb_key_attributes_translator.h
+++ b/components/service/crypto/provider/serializer/protobuf/pb_key_attributes_translator.h
@@ -10,7 +10,7 @@
 #include <service/crypto/protobuf/key_attributes.pb.h>
 #include <psa/crypto.h>
 
-extern void pb_crypto_provider_translate_key_attributes(
+void pb_crypto_provider_translate_key_attributes(
     psa_key_attributes_t *psa_attributes,
     const ts_crypto_KeyAttributes *proto_attributes);
 
diff --git a/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp b/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp
new file mode 100644
index 0000000..40910fa
--- /dev/null
+++ b/components/service/crypto/test/protocol/check_crypto_opcode_alignment.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <service/crypto/protobuf/opcodes.pb.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Check alignment of Crypto service opcode definitions
+ */
+TEST_GROUP(CryptoProtocolOpcodeChecks)
+{
+
+};
+
+TEST(CryptoProtocolOpcodeChecks, checkPackedcToProtobuf)
+{
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_KEY, ts_crypto_Opcode_GENERATE_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_DESTROY_KEY, ts_crypto_Opcode_DESTROY_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_OPEN_KEY, ts_crypto_Opcode_OPEN_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_CLOSE_KEY, ts_crypto_Opcode_CLOSE_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_KEY, ts_crypto_Opcode_EXPORT_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY, ts_crypto_Opcode_EXPORT_PUBLIC_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_IMPORT_KEY, ts_crypto_Opcode_IMPORT_KEY);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_SIGN_HASH, ts_crypto_Opcode_SIGN_HASH);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_VERIFY_HASH, ts_crypto_Opcode_VERIFY_HASH);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT, ts_crypto_Opcode_ASYMMETRIC_DECRYPT);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT, ts_crypto_Opcode_ASYMMETRIC_ENCRYPT);
+    CHECK_EQUAL(TS_CRYPTO_OPCODE_GENERATE_RANDOM, ts_crypto_Opcode_GENERATE_RANDOM);
+}
+
diff --git a/components/service/crypto/test/protocol/check_crypto_packed-c_protocol_alignment.cpp b/components/service/crypto/test/protocol/check_crypto_packed-c_protocol_alignment.cpp
new file mode 100644
index 0000000..ff7ee0f
--- /dev/null
+++ b/components/service/crypto/test/protocol/check_crypto_packed-c_protocol_alignment.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/key_attributes.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Check alignment of Crypto service packed-c protocol definitions for
+ * alignment with PSA C API definitions.
+ */
+TEST_GROUP(CryptoProtocolPackedcChecks)
+{
+
+};
+
+TEST(CryptoProtocolPackedcChecks, checkKeyType)
+{
+    /*
+     * Check alignment between PSA and protobuf key type definitions
+     */
+    CHECK_EQUAL(PSA_KEY_TYPE_RAW_DATA, TS_CRYPTO_KEY_TYPE_RAW_DATA);
+    CHECK_EQUAL(PSA_KEY_TYPE_HMAC, TS_CRYPTO_KEY_TYPE_HMAC);
+    CHECK_EQUAL(PSA_KEY_TYPE_DERIVE, TS_CRYPTO_KEY_TYPE_DERIVE);
+    CHECK_EQUAL(PSA_KEY_TYPE_AES, TS_CRYPTO_KEY_TYPE_AES);
+    CHECK_EQUAL(PSA_KEY_TYPE_DES, TS_CRYPTO_KEY_TYPE_DES);
+    CHECK_EQUAL(PSA_KEY_TYPE_CAMELLIA, TS_CRYPTO_KEY_TYPE_CAMELLIA);
+    CHECK_EQUAL(PSA_KEY_TYPE_ARC4, TS_CRYPTO_KEY_TYPE_ARC4);
+    CHECK_EQUAL(PSA_KEY_TYPE_CHACHA20, TS_CRYPTO_KEY_TYPE_CHACHA20);
+    CHECK_EQUAL(PSA_KEY_TYPE_RSA_PUBLIC_KEY, TS_CRYPTO_KEY_TYPE_RSA_PUBLIC_KEY);
+    CHECK_EQUAL(PSA_KEY_TYPE_RSA_KEY_PAIR, TS_CRYPTO_KEY_TYPE_RSA_KEY_PAIR);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE, TS_CRYPTO_KEY_TYPE_ECC_PUBLIC_KEY_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_KEY_PAIR_BASE, TS_CRYPTO_KEY_TYPE_ECC_KEY_PAIR_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_CURVE_MASK, TS_CRYPTO_KEY_TYPE_ECC_CURVE_MASK);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE, TS_CRYPTO_KEY_TYPE_DH_PUBLIC_KEY_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_KEY_PAIR_BASE, TS_CRYPTO_KEY_TYPE_DH_KEY_PAIR_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_GROUP_MASK, TS_CRYPTO_KEY_TYPE_DH_GROUP_MASK);
+}
+
+TEST(CryptoProtocolPackedcChecks, checkEccCurve)
+{
+    /*
+     * ECC curves for use with ECC Key types
+     */
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_K1, TS_CRYPTO_ECC_CURVE_SECP_K1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_R1, TS_CRYPTO_ECC_CURVE_SECP_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_R2, TS_CRYPTO_ECC_CURVE_SECP_R2);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_K1, TS_CRYPTO_ECC_CURVE_SECT_K1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_R1, TS_CRYPTO_ECC_CURVE_SECT_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_R2, TS_CRYPTO_ECC_CURVE_SECT_R2);
+    CHECK_EQUAL(PSA_ECC_CURVE_BRAINPOOL_P_R1, TS_CRYPTO_ECC_CURVE_BRAINPOOL_P_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_MONTGOMERY, TS_CRYPTO_ECC_CURVE_MONTGOMERY);
+}
+
+TEST(CryptoProtocolPackedcChecks, checkDhGroup)
+{
+    /*
+     * Diffie-Hellman groups for use with DH key types
+     */
+    CHECK_EQUAL(PSA_DH_GROUP_RFC7919, TS_CRYPTO_DH_GROUP_RFC7919);
+}
+
+TEST(CryptoProtocolPackedcChecks, checkAlg)
+{
+    /*
+     * Crypto algorithms
+     */
+    CHECK_EQUAL(PSA_ALG_HASH_MASK, TS_CRYPTO_ALG_HASH_MASK);
+    CHECK_EQUAL(PSA_ALG_MD2, TS_CRYPTO_ALG_MD2);
+    CHECK_EQUAL(PSA_ALG_MD4, TS_CRYPTO_ALG_MD4);
+    CHECK_EQUAL(PSA_ALG_MD5, TS_CRYPTO_ALG_MD5);
+    CHECK_EQUAL(PSA_ALG_RIPEMD160, TS_CRYPTO_ALG_RIPEMD160);
+    CHECK_EQUAL(PSA_ALG_SHA_1, TS_CRYPTO_ALG_SHA_1);
+    CHECK_EQUAL(PSA_ALG_SHA_224, TS_CRYPTO_ALG_SHA_224);
+    CHECK_EQUAL(PSA_ALG_SHA_256, TS_CRYPTO_ALG_SHA_256);
+    CHECK_EQUAL(PSA_ALG_SHA_384, TS_CRYPTO_ALG_SHA_384);
+    CHECK_EQUAL(PSA_ALG_SHA_512, TS_CRYPTO_ALG_SHA_512);
+    CHECK_EQUAL(PSA_ALG_SHA_512_224, TS_CRYPTO_ALG_SHA_512_224);
+    CHECK_EQUAL(PSA_ALG_SHA_512_256, TS_CRYPTO_ALG_SHA_512_256);
+    CHECK_EQUAL(PSA_ALG_SHA3_224, TS_CRYPTO_ALG_SHA3_224);
+    CHECK_EQUAL(PSA_ALG_SHA3_256, TS_CRYPTO_ALG_SHA3_256);
+    CHECK_EQUAL(PSA_ALG_SHA3_384, TS_CRYPTO_ALG_SHA3_384);
+    CHECK_EQUAL(PSA_ALG_SHA3_512, TS_CRYPTO_ALG_SHA3_512);
+    CHECK_EQUAL(PSA_ALG_CBC_MAC, TS_CRYPTO_ALG_CBC_MAC);
+    CHECK_EQUAL(PSA_ALG_CMAC, TS_CRYPTO_ALG_CMAC);
+    CHECK_EQUAL(PSA_ALG_ARC4, TS_CRYPTO_ALG_ARC4);
+    CHECK_EQUAL(PSA_ALG_CHACHA20, TS_CRYPTO_ALG_CHACHA20);
+    CHECK_EQUAL(PSA_ALG_CTR, TS_CRYPTO_ALG_CTR);
+    CHECK_EQUAL(PSA_ALG_CFB, TS_CRYPTO_ALG_CFB);
+    CHECK_EQUAL(PSA_ALG_OFB, TS_CRYPTO_ALG_OFB);
+    CHECK_EQUAL(PSA_ALG_XTS, TS_CRYPTO_ALG_XTS);
+    CHECK_EQUAL(PSA_ALG_CBC_NO_PADDING, TS_CRYPTO_ALG_CBC_NO_PADDING);
+    CHECK_EQUAL(PSA_ALG_CBC_PKCS7, TS_CRYPTO_ALG_CBC_PKCS7);
+    CHECK_EQUAL(PSA_ALG_AEAD_FROM_BLOCK_FLAG, TS_CRYPTO_ALG_AEAD_FROM_BLOCK_FLAG);
+    CHECK_EQUAL(PSA_ALG_CCM, TS_CRYPTO_ALG_CCM);
+    CHECK_EQUAL(PSA_ALG_GCM, TS_CRYPTO_ALG_GCM);
+    CHECK_EQUAL(PSA_ALG_CHACHA20_POLY1305, TS_CRYPTO_ALG_CHACHA20_POLY1305);
+    CHECK_EQUAL(PSA_ALG_RSA_PKCS1V15_SIGN_BASE, TS_CRYPTO_ALG_RSA_PKCS1V15_SIGN_BASE);
+    CHECK_EQUAL(PSA_ALG_RSA_PSS_BASE, TS_CRYPTO_ALG_RSA_PSS_BASE);
+    CHECK_EQUAL(PSA_ALG_ECDSA_BASE, TS_CRYPTO_ALG_ECDSA_BASE);
+    CHECK_EQUAL(PSA_ALG_DETERMINISTIC_ECDSA_BASE, TS_CRYPTO_ALG_DETERMINISTIC_ECDSA_BASE);
+    CHECK_EQUAL(PSA_ALG_RSA_PKCS1V15_CRYPT, TS_CRYPTO_ALG_RSA_PKCS1V15_CRYPT);
+    CHECK_EQUAL(PSA_ALG_RSA_OAEP_BASE, TS_CRYPTO_ALG_RSA_OAEP_BASE);
+    CHECK_EQUAL(PSA_ALG_HKDF_BASE, TS_CRYPTO_ALG_HKDF_BASE);
+    CHECK_EQUAL(PSA_ALG_TLS12_PRF_BASE, TS_CRYPTO_ALG_TLS12_PRF_BASE);
+    CHECK_EQUAL(PSA_ALG_TLS12_PSK_TO_MS_BASE, TS_CRYPTO_ALG_TLS12_PSK_TO_MS_BASE);
+    CHECK_EQUAL(PSA_ALG_KEY_DERIVATION_MASK, TS_CRYPTO_ALG_KEY_DERIVATION_MASK);
+    CHECK_EQUAL(PSA_ALG_KEY_AGREEMENT_MASK, TS_CRYPTO_ALG_KEY_AGREEMENT_MASK);
+    CHECK_EQUAL(PSA_ALG_FFDH, TS_CRYPTO_ALG_FFDH);
+    CHECK_EQUAL(PSA_ALG_ECDH, TS_CRYPTO_ALG_ECDH);
+}
+
+TEST(CryptoProtocolPackedcChecks, checkKeyLifetime)
+{
+    /*
+     * Key lifetime
+     */
+    CHECK_EQUAL(PSA_KEY_LIFETIME_VOLATILE, TS_CRYPTO_KEY_LIFETIME_VOLATILE);
+    CHECK_EQUAL(PSA_KEY_LIFETIME_PERSISTENT, TS_CRYPTO_KEY_LIFETIME_PERSISTENT);
+}
+
+TEST(CryptoProtocolPackedcChecks, checkKeyUsage)
+{
+    /*
+     * Key usage constraints
+     */
+    CHECK_EQUAL(PSA_KEY_USAGE_EXPORT, TS_CRYPTO_KEY_USAGE_EXPORT);
+    CHECK_EQUAL(PSA_KEY_USAGE_COPY, TS_CRYPTO_KEY_USAGE_COPY);
+    CHECK_EQUAL(PSA_KEY_USAGE_ENCRYPT, TS_CRYPTO_KEY_USAGE_ENCRYPT);
+    CHECK_EQUAL(PSA_KEY_USAGE_DECRYPT, TS_CRYPTO_KEY_USAGE_DECRYPT);
+    CHECK_EQUAL(PSA_KEY_USAGE_SIGN_HASH, TS_CRYPTO_KEY_USAGE_SIGN_HASH);
+    CHECK_EQUAL(PSA_KEY_USAGE_VERIFY_HASH, TS_CRYPTO_KEY_USAGE_VERIFY_HASH);
+    CHECK_EQUAL(PSA_KEY_USAGE_DERIVE, TS_CRYPTO_KEY_USAGE_DERIVE);
+}
\ No newline at end of file
diff --git a/components/service/crypto/test/protocol/check_crypto_protobuf_protocol_alignment.cpp b/components/service/crypto/test/protocol/check_crypto_protobuf_protocol_alignment.cpp
new file mode 100644
index 0000000..16f8cba
--- /dev/null
+++ b/components/service/crypto/test/protocol/check_crypto_protobuf_protocol_alignment.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <psa/crypto.h>
+#include <service/crypto/protobuf/key_attributes.pb.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Check alignment of Crypto service protobuf protocol definitions for
+ * alignment with PSA C API definitions.
+ */
+TEST_GROUP(CryptoProtocolProtobufChecks)
+{
+
+};
+
+TEST(CryptoProtocolProtobufChecks, checkKeyType)
+{
+    /*
+     * Check alignment between PSA and protobuf key type definitions
+     */
+    CHECK_EQUAL(PSA_KEY_TYPE_RAW_DATA, ts_crypto_KeyType_KEY_TYPE_RAW_DATA);
+    CHECK_EQUAL(PSA_KEY_TYPE_HMAC, ts_crypto_KeyType_KEY_TYPE_HMAC);
+    CHECK_EQUAL(PSA_KEY_TYPE_DERIVE, ts_crypto_KeyType_KEY_TYPE_DERIVE);
+    CHECK_EQUAL(PSA_KEY_TYPE_AES, ts_crypto_KeyType_KEY_TYPE_AES);
+    CHECK_EQUAL(PSA_KEY_TYPE_DES, ts_crypto_KeyType_KEY_TYPE_DES);
+    CHECK_EQUAL(PSA_KEY_TYPE_CAMELLIA, ts_crypto_KeyType_KEY_TYPE_CAMELLIA);
+    CHECK_EQUAL(PSA_KEY_TYPE_ARC4, ts_crypto_KeyType_KEY_TYPE_ARC4);
+    CHECK_EQUAL(PSA_KEY_TYPE_CHACHA20, ts_crypto_KeyType_KEY_TYPE_CHACHA20);
+    CHECK_EQUAL(PSA_KEY_TYPE_RSA_PUBLIC_KEY, ts_crypto_KeyType_KEY_TYPE_RSA_PUBLIC_KEY);
+    CHECK_EQUAL(PSA_KEY_TYPE_RSA_KEY_PAIR, ts_crypto_KeyType_KEY_TYPE_RSA_KEY_PAIR);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE, ts_crypto_KeyType_KEY_TYPE_ECC_PUBLIC_KEY_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_KEY_PAIR_BASE, ts_crypto_KeyType_KEY_TYPE_ECC_KEY_PAIR_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_ECC_CURVE_MASK, ts_crypto_KeyType_KEY_TYPE_ECC_CURVE_MASK);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE, ts_crypto_KeyType_KEY_TYPE_DH_PUBLIC_KEY_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_KEY_PAIR_BASE, ts_crypto_KeyType_KEY_TYPE_DH_KEY_PAIR_BASE);
+    CHECK_EQUAL(PSA_KEY_TYPE_DH_GROUP_MASK, ts_crypto_KeyType_KEY_TYPE_DH_GROUP_MASK);
+}
+
+TEST(CryptoProtocolProtobufChecks, checkEccCurve)
+{
+    /*
+     * ECC curves for use with ECC Key types
+     */
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_K1, ts_crypto_EccCurve_ECC_CURVE_SECP_K1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_R1, ts_crypto_EccCurve_ECC_CURVE_SECP_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECP_R2, ts_crypto_EccCurve_ECC_CURVE_SECP_R2);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_K1, ts_crypto_EccCurve_ECC_CURVE_SECT_K1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_R1, ts_crypto_EccCurve_ECC_CURVE_SECT_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_SECT_R2, ts_crypto_EccCurve_ECC_CURVE_SECT_R2);
+    CHECK_EQUAL(PSA_ECC_CURVE_BRAINPOOL_P_R1, ts_crypto_EccCurve_ECC_CURVE_BRAINPOOL_P_R1);
+    CHECK_EQUAL(PSA_ECC_CURVE_MONTGOMERY, ts_crypto_EccCurve_ECC_CURVE_MONTGOMERY);
+}
+
+TEST(CryptoProtocolProtobufChecks, checkDhGroup)
+{
+    /*
+     * Diffie-Hellman groups for use with DH key types
+     */
+    CHECK_EQUAL(PSA_DH_GROUP_RFC7919, ts_crypto_DhGroup_DH_GROUP_RFC7919);
+}
+
+TEST(CryptoProtocolProtobufChecks, checkAlg)
+{
+    /*
+     * Crypto algorithms
+     */
+    CHECK_EQUAL(PSA_ALG_HASH_MASK, ts_crypto_Alg_ALG_HASH_MASK);
+    CHECK_EQUAL(PSA_ALG_MD2, ts_crypto_Alg_ALG_MD2);
+    CHECK_EQUAL(PSA_ALG_MD4, ts_crypto_Alg_ALG_MD4);
+    CHECK_EQUAL(PSA_ALG_MD5, ts_crypto_Alg_ALG_MD5);
+    CHECK_EQUAL(PSA_ALG_RIPEMD160, ts_crypto_Alg_ALG_RIPEMD160);
+    CHECK_EQUAL(PSA_ALG_SHA_1, ts_crypto_Alg_ALG_SHA_1);
+    CHECK_EQUAL(PSA_ALG_SHA_224, ts_crypto_Alg_ALG_SHA_224);
+    CHECK_EQUAL(PSA_ALG_SHA_256, ts_crypto_Alg_ALG_SHA_256);
+    CHECK_EQUAL(PSA_ALG_SHA_384, ts_crypto_Alg_ALG_SHA_384);
+    CHECK_EQUAL(PSA_ALG_SHA_512, ts_crypto_Alg_ALG_SHA_512);
+    CHECK_EQUAL(PSA_ALG_SHA_512_224, ts_crypto_Alg_ALG_SHA_512_224);
+    CHECK_EQUAL(PSA_ALG_SHA_512_256, ts_crypto_Alg_ALG_SHA_512_256);
+    CHECK_EQUAL(PSA_ALG_SHA3_224, ts_crypto_Alg_ALG_SHA3_224);
+    CHECK_EQUAL(PSA_ALG_SHA3_256, ts_crypto_Alg_ALG_SHA3_256);
+    CHECK_EQUAL(PSA_ALG_SHA3_384, ts_crypto_Alg_ALG_SHA3_384);
+    CHECK_EQUAL(PSA_ALG_SHA3_512, ts_crypto_Alg_ALG_SHA3_512);
+    CHECK_EQUAL(PSA_ALG_CBC_MAC, ts_crypto_Alg_ALG_CBC_MAC);
+    CHECK_EQUAL(PSA_ALG_CMAC, ts_crypto_Alg_ALG_CMAC);
+    CHECK_EQUAL(PSA_ALG_ARC4, ts_crypto_Alg_ALG_ARC4);
+    CHECK_EQUAL(PSA_ALG_CHACHA20, ts_crypto_Alg_ALG_CHACHA20);
+    CHECK_EQUAL(PSA_ALG_CTR, ts_crypto_Alg_ALG_CTR);
+    CHECK_EQUAL(PSA_ALG_CFB, ts_crypto_Alg_ALG_CFB);
+    CHECK_EQUAL(PSA_ALG_OFB, ts_crypto_Alg_ALG_OFB);
+    CHECK_EQUAL(PSA_ALG_XTS, ts_crypto_Alg_ALG_XTS);
+    CHECK_EQUAL(PSA_ALG_CBC_NO_PADDING, ts_crypto_Alg_ALG_CBC_NO_PADDING);
+    CHECK_EQUAL(PSA_ALG_CBC_PKCS7, ts_crypto_Alg_ALG_CBC_PKCS7);
+    CHECK_EQUAL(PSA_ALG_AEAD_FROM_BLOCK_FLAG, ts_crypto_Alg_ALG_AEAD_FROM_BLOCK_FLAG);
+    CHECK_EQUAL(PSA_ALG_CCM, ts_crypto_Alg_ALG_CCM);
+    CHECK_EQUAL(PSA_ALG_GCM, ts_crypto_Alg_ALG_GCM);
+    CHECK_EQUAL(PSA_ALG_CHACHA20_POLY1305, ts_crypto_Alg_ALG_CHACHA20_POLY1305);
+    CHECK_EQUAL(PSA_ALG_RSA_PKCS1V15_SIGN_BASE, ts_crypto_Alg_ALG_RSA_PKCS1V15_SIGN_BASE);
+    CHECK_EQUAL(PSA_ALG_RSA_PSS_BASE, ts_crypto_Alg_ALG_RSA_PSS_BASE);
+    CHECK_EQUAL(PSA_ALG_ECDSA_BASE, ts_crypto_Alg_ALG_ECDSA_BASE);
+    CHECK_EQUAL(PSA_ALG_DETERMINISTIC_ECDSA_BASE, ts_crypto_Alg_ALG_DETERMINISTIC_ECDSA_BASE);
+    CHECK_EQUAL(PSA_ALG_RSA_PKCS1V15_CRYPT, ts_crypto_Alg_ALG_RSA_PKCS1V15_CRYPT);
+    CHECK_EQUAL(PSA_ALG_RSA_OAEP_BASE, ts_crypto_Alg_ALG_RSA_OAEP_BASE);
+    CHECK_EQUAL(PSA_ALG_HKDF_BASE, ts_crypto_Alg_ALG_HKDF_BASE);
+    CHECK_EQUAL(PSA_ALG_TLS12_PRF_BASE, ts_crypto_Alg_ALG_TLS12_PRF_BASE);
+    CHECK_EQUAL(PSA_ALG_TLS12_PSK_TO_MS_BASE, ts_crypto_Alg_ALG_TLS12_PSK_TO_MS_BASE);
+    CHECK_EQUAL(PSA_ALG_KEY_DERIVATION_MASK, ts_crypto_Alg_ALG_KEY_DERIVATION_MASK);
+    CHECK_EQUAL(PSA_ALG_KEY_AGREEMENT_MASK, ts_crypto_Alg_ALG_KEY_AGREEMENT_MASK);
+    CHECK_EQUAL(PSA_ALG_FFDH, ts_crypto_Alg_ALG_FFDH);
+    CHECK_EQUAL(PSA_ALG_ECDH, ts_crypto_Alg_ALG_ECDH);
+}
+
+TEST(CryptoProtocolProtobufChecks, checkKeyLifetime)
+{
+    /*
+     * Key lifetime
+     */
+    CHECK_EQUAL(PSA_KEY_LIFETIME_VOLATILE, ts_crypto_KeyLifetime_KEY_LIFETIME_VOLATILE);
+    CHECK_EQUAL(PSA_KEY_LIFETIME_PERSISTENT, ts_crypto_KeyLifetime_KEY_LIFETIME_PERSISTENT);
+}
+
+TEST(CryptoProtocolProtobufChecks, checkKeyUsage)
+{
+    /*
+     * Key usage constraints
+     */
+    CHECK_EQUAL(PSA_KEY_USAGE_EXPORT, ts_crypto_KeyUsage_KEY_USAGE_EXPORT);
+    CHECK_EQUAL(PSA_KEY_USAGE_COPY, ts_crypto_KeyUsage_KEY_USAGE_COPY);
+    CHECK_EQUAL(PSA_KEY_USAGE_ENCRYPT, ts_crypto_KeyUsage_KEY_USAGE_ENCRYPT);
+    CHECK_EQUAL(PSA_KEY_USAGE_DECRYPT, ts_crypto_KeyUsage_KEY_USAGE_DECRYPT);
+    CHECK_EQUAL(PSA_KEY_USAGE_SIGN_HASH, ts_crypto_KeyUsage_KEY_USAGE_SIGN_HASH);
+    CHECK_EQUAL(PSA_KEY_USAGE_VERIFY_HASH, ts_crypto_KeyUsage_KEY_USAGE_VERIFY_HASH);
+    CHECK_EQUAL(PSA_KEY_USAGE_DERIVE, ts_crypto_KeyUsage_KEY_USAGE_DERIVE);
+}
diff --git a/components/service/crypto/test/protocol/component.cmake b/components/service/crypto/test/protocol/component.cmake
new file mode 100644
index 0000000..ed590bc
--- /dev/null
+++ b/components/service/crypto/test/protocol/component.cmake
@@ -0,0 +1,16 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/check_crypto_opcode_alignment.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/check_crypto_protobuf_protocol_alignment.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/check_crypto_packed-c_protocol_alignment.cpp"
+	)
+
diff --git a/components/service/crypto/test/service/component.cmake b/components/service/crypto/test/service/component.cmake
index 26366fd..8aad320 100644
--- a/components/service/crypto/test/service/component.cmake
+++ b/components/service/crypto/test/service/component.cmake
@@ -1,5 +1,5 @@
 #-------------------------------------------------------------------------------
-# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -9,7 +9,7 @@
 endif()
 
 target_sources(${TGT} PRIVATE
-	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_op_tests.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_scenarios.cpp"
 	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_limit_tests.cpp"
 	)
 
diff --git a/components/service/crypto/test/service/crypto_service_limit_tests.cpp b/components/service/crypto/test/service/crypto_service_limit_tests.cpp
index 392391a..2bb19f9 100644
--- a/components/service/crypto/test/service/crypto_service_limit_tests.cpp
+++ b/components/service/crypto/test/service/crypto_service_limit_tests.cpp
@@ -8,7 +8,7 @@
 #include <vector>
 #include <cstring>
 #include <cstdint>
-#include <service/crypto/client/cpp/crypto_client.h>
+#include <service/crypto/client/cpp/protobuf/protobuf_crypto_client.h>
 #include <protocols/rpc/common/packed-c/encoding.h>
 #include <service_locator.h>
 #include <CppUTest/TestHarness.h>
@@ -36,7 +36,7 @@
         m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PROTOBUF, &caller);
         CHECK(m_rpc_session_handle);
 
-        m_crypto_client = new crypto_client(caller);
+        m_crypto_client = new protobuf_crypto_client(caller);
     }
 
     void teardown()
diff --git a/components/service/crypto/test/service/crypto_service_op_tests.cpp b/components/service/crypto/test/service/crypto_service_scenarios.cpp
similarity index 85%
rename from components/service/crypto/test/service/crypto_service_op_tests.cpp
rename to components/service/crypto/test/service/crypto_service_scenarios.cpp
index 569a196..80d7279 100644
--- a/components/service/crypto/test/service/crypto_service_op_tests.cpp
+++ b/components/service/crypto/test/service/crypto_service_scenarios.cpp
@@ -7,56 +7,23 @@
 #include <string>
 #include <cstring>
 #include <cstdint>
-#include <service/crypto/client/cpp/crypto_client.h>
-#include <protocols/rpc/common/packed-c/encoding.h>
-#include <service_locator.h>
 #include <CppUTest/TestHarness.h>
+#include "crypto_service_scenarios.h"
 
-/*
- * Service-level tests that focus on exercising each supported operation.
- * These are mainly valid behaviour tests with the goal of checking
- * that the number of operations supported is as expected.
- */
-TEST_GROUP(CryptoServiceOpTests)
+
+crypto_service_scenarios::crypto_service_scenarios(crypto_client *crypto_client) :
+    m_crypto_client(crypto_client)
 {
-    void setup()
-    {
-        struct rpc_caller *caller;
-        int status;
 
-        m_rpc_session_handle = NULL;
-        m_crypto_service_context = NULL;
-        m_crypto_client = NULL;
+}
 
-        service_locator_init();
+crypto_service_scenarios::~crypto_service_scenarios()
+{
+    delete m_crypto_client;
+    m_crypto_client = NULL;
+}
 
-        m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
-        CHECK_TRUE(m_crypto_service_context);
-
-        m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PROTOBUF, &caller);
-        CHECK_TRUE(m_rpc_session_handle);
-
-        m_crypto_client = new crypto_client(caller);
-    }
-
-    void teardown()
-    {
-        delete m_crypto_client;
-        m_crypto_client = NULL;
-
-        service_context_close(m_crypto_service_context, m_rpc_session_handle);
-        m_rpc_session_handle = NULL;
-
-        service_context_relinquish(m_crypto_service_context);
-        m_crypto_service_context = NULL;
-    }
-
-    rpc_session_handle m_rpc_session_handle;
-    struct service_context *m_crypto_service_context;
-    crypto_client *m_crypto_client;
-};
-
-TEST(CryptoServiceOpTests, generateVolatileKeys)
+void crypto_service_scenarios::generateVolatileKeys()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -89,7 +56,7 @@
     psa_reset_key_attributes(&attributes);
 }
 
-TEST(CryptoServiceOpTests, generatePersistentKeys)
+void crypto_service_scenarios::generatePersistentKeys()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -151,7 +118,7 @@
     psa_reset_key_attributes(&attributes);
 }
 
-TEST(CryptoServiceOpTests, exportPublicKey)
+void crypto_service_scenarios::exportPublicKey()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -175,14 +142,14 @@
 
     status = m_crypto_client->export_public_key(key_handle, key_buf, sizeof(key_buf), &key_len);
     CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK(key_len > 0);
+    CHECK_TRUE(key_len > 0);
 
     /* Remove the key */
     status = m_crypto_client->destroy_key(key_handle);
     CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
-TEST(CryptoServiceOpTests, exportAndImportKeyPair)
+void crypto_service_scenarios::exportAndImportKeyPair()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -221,7 +188,7 @@
     CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
-TEST(CryptoServiceOpTests, signAndVerifyHash)
+void crypto_service_scenarios::signAndVerifyHash()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -271,7 +238,7 @@
     CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
-TEST(CryptoServiceOpTests, asymEncryptDecrypt)
+void crypto_service_scenarios::asymEncryptDecrypt()
 {
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
@@ -310,14 +277,14 @@
 
     /* Expect the encrypted/decrypted message to match theh original */
     CHECK_EQUAL(sizeof(message), plaintext_len);
-    CHECK(memcmp(message, plaintext, plaintext_len) == 0);
+    MEMCMP_EQUAL(message, plaintext, plaintext_len);
 
     /* Remove the key */
     status = m_crypto_client->destroy_key(key_handle);
     CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
-TEST(CryptoServiceOpTests, generateRandomNumbers)
+void crypto_service_scenarios::generateRandomNumbers()
 {
     psa_status_t status;
     uint8_t num1_8bit[1];
@@ -373,9 +340,7 @@
     status = m_crypto_client->generate_random(num12_128bit, sizeof(num12_128bit));
     CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Expect different numbers to be generated */
-    CHECK(memcmp(num1_8bit, num2_8bit, sizeof(num1_8bit)) != 0);
-    CHECK(memcmp(num3_16bit, num4_16bit, sizeof(num3_16bit)) != 0);
+    /* For larger numbers, it should be improbable that numbers are the same  */
     CHECK(memcmp(num5_24bit, num6_24bit, sizeof(num5_24bit)) != 0);
     CHECK(memcmp(num7_32bit, num8_32bit, sizeof(num7_32bit)) != 0);
     CHECK(memcmp(num9_64bit, num10_64bit, sizeof(num9_64bit)) != 0);
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.h b/components/service/crypto/test/service/crypto_service_scenarios.h
new file mode 100644
index 0000000..2c7d188
--- /dev/null
+++ b/components/service/crypto/test/service/crypto_service_scenarios.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/crypto/client/cpp/crypto_client.h>
+
+/*
+ * Service-level test scenarios for the crypto service that may be reused using
+ * different concrete crypto_clients to check end-to-end operation using different
+ * protocol serialization schemes.
+ */
+class crypto_service_scenarios
+{
+public:
+    crypto_service_scenarios(crypto_client *crypto_client);
+    ~crypto_service_scenarios();
+
+    void generateRandomNumbers();
+    void asymEncryptDecrypt();
+    void signAndVerifyHash();
+    void exportAndImportKeyPair();
+    void exportPublicKey();
+    void generatePersistentKeys();
+    void generateVolatileKeys();
+
+private:
+    crypto_client *m_crypto_client;
+};
diff --git a/components/service/crypto/test/service/packed-c/component.cmake b/components/service/crypto/test/service/packed-c/component.cmake
new file mode 100644
index 0000000..fcd6b20
--- /dev/null
+++ b/components/service/crypto/test/service/packed-c/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_packedc_tests.cpp"
+	)
+
diff --git a/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
new file mode 100644
index 0000000..132bbc8
--- /dev/null
+++ b/components/service/crypto/test/service/packed-c/crypto_service_packedc_tests.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/crypto/client/cpp/packed-c/packedc_crypto_client.h>
+#include <service/crypto/test/service/crypto_service_scenarios.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service_locator.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Service-level tests that use the Protobuf access protocol serialization
+ */
+TEST_GROUP(CryptoServicePackedcTests)
+{
+    void setup()
+    {
+        struct rpc_caller *caller;
+        int status;
+
+        m_rpc_session_handle = NULL;
+        m_crypto_service_context = NULL;
+        m_scenarios = NULL;
+
+        service_locator_init();
+
+        m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+        CHECK_TRUE(m_crypto_service_context);
+
+        m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PACKED_C, &caller);
+        CHECK_TRUE(m_rpc_session_handle);
+
+        m_scenarios = new crypto_service_scenarios(new packedc_crypto_client(caller));
+    }
+
+    void teardown()
+    {
+        delete m_scenarios;
+        m_scenarios = NULL;
+
+        service_context_close(m_crypto_service_context, m_rpc_session_handle);
+        m_rpc_session_handle = NULL;
+
+        service_context_relinquish(m_crypto_service_context);
+        m_crypto_service_context = NULL;
+    }
+
+    rpc_session_handle m_rpc_session_handle;
+    struct service_context *m_crypto_service_context;
+    crypto_service_scenarios *m_scenarios;
+};
+
+TEST(CryptoServicePackedcTests, generateVolatileKeys)
+{
+    m_scenarios->generateVolatileKeys();
+}
+
+TEST(CryptoServicePackedcTests, generatePersistentKeys)
+{
+    m_scenarios->generatePersistentKeys();
+}
+
+TEST(CryptoServicePackedcTests, exportPublicKey)
+{
+    m_scenarios->exportPublicKey();
+}
+
+TEST(CryptoServicePackedcTests, exportAndImportKeyPair)
+{
+    m_scenarios->exportAndImportKeyPair();
+}
+
+TEST(CryptoServicePackedcTests, signAndVerifyHash)
+{
+    m_scenarios->signAndVerifyHash();
+}
+
+TEST(CryptoServicePackedcTests, asymEncryptDecrypt)
+{
+    m_scenarios->asymEncryptDecrypt();
+}
+
+TEST(CryptoServicePackedcTests, generateRandomNumbers)
+{
+    m_scenarios->generateRandomNumbers();
+}
diff --git a/components/service/crypto/test/service/protobuf/component.cmake b/components/service/crypto/test/service/protobuf/component.cmake
new file mode 100644
index 0000000..8d12774
--- /dev/null
+++ b/components/service/crypto/test/service/protobuf/component.cmake
@@ -0,0 +1,14 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_protobuf_tests.cpp"
+	)
+
diff --git a/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp b/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp
new file mode 100644
index 0000000..3d728e2
--- /dev/null
+++ b/components/service/crypto/test/service/protobuf/crypto_service_protobuf_tests.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <service/crypto/client/cpp/protobuf/protobuf_crypto_client.h>
+#include <service/crypto/test/service/crypto_service_scenarios.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+#include <service_locator.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Service-level tests that use the Protobuf access protocol serialization
+ */
+TEST_GROUP(CryptoServiceProtobufTests)
+{
+    void setup()
+    {
+        struct rpc_caller *caller;
+        int status;
+
+        m_rpc_session_handle = NULL;
+        m_crypto_service_context = NULL;
+        m_scenarios = NULL;
+
+        service_locator_init();
+
+        m_crypto_service_context = service_locator_query("sn:trustedfirmware.org:crypto:0", &status);
+        CHECK_TRUE(m_crypto_service_context);
+
+        m_rpc_session_handle = service_context_open(m_crypto_service_context, TS_RPC_ENCODING_PROTOBUF, &caller);
+        CHECK_TRUE(m_rpc_session_handle);
+
+        m_scenarios = new crypto_service_scenarios(new protobuf_crypto_client(caller));
+    }
+
+    void teardown()
+    {
+        delete m_scenarios;
+        m_scenarios = NULL;
+
+        service_context_close(m_crypto_service_context, m_rpc_session_handle);
+        m_rpc_session_handle = NULL;
+
+        service_context_relinquish(m_crypto_service_context);
+        m_crypto_service_context = NULL;
+    }
+
+    rpc_session_handle m_rpc_session_handle;
+    struct service_context *m_crypto_service_context;
+    crypto_service_scenarios *m_scenarios;
+};
+
+TEST(CryptoServiceProtobufTests, generateVolatileKeys)
+{
+    m_scenarios->generateVolatileKeys();
+}
+
+TEST(CryptoServiceProtobufTests, generatePersistentKeys)
+{
+    m_scenarios->generatePersistentKeys();
+}
+
+TEST(CryptoServiceProtobufTests, exportPublicKey)
+{
+    m_scenarios->exportPublicKey();
+}
+
+TEST(CryptoServiceProtobufTests, exportAndImportKeyPair)
+{
+    m_scenarios->exportAndImportKeyPair();
+}
+
+TEST(CryptoServiceProtobufTests, signAndVerifyHash)
+{
+    m_scenarios->signAndVerifyHash();
+}
+
+TEST(CryptoServiceProtobufTests, asymEncryptDecrypt)
+{
+    m_scenarios->asymEncryptDecrypt();
+}
+
+TEST(CryptoServiceProtobufTests, generateRandomNumbers)
+{
+    m_scenarios->generateRandomNumbers();
+}