Add hash operation support to Crypto service provider

Adds support for multi-step hash operations.  Only includes
protocol support for packed-c serialization at the moment.
Protobuf serialization still needs to be added.  Includes
crypto context management that can be used for any multi-
step operations such as MAC and symmetric encrypt/decrypt.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Ib51a9737f1987e1e7531da7edb38d9dc4095cc7e
diff --git a/components/service/crypto/client/cpp/crypto_client.h b/components/service/crypto/client/cpp/crypto_client.h
index 4884344..03cf4b3 100644
--- a/components/service/crypto/client/cpp/crypto_client.h
+++ b/components/service/crypto/client/cpp/crypto_client.h
@@ -24,7 +24,8 @@
     int err_rpc_status() const;
 
     /* Key lifecycle methods */
-    virtual psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id) = 0;
+    virtual psa_status_t generate_key(const psa_key_attributes_t *attributes,
+                            psa_key_id_t *id) = 0;
     virtual psa_status_t destroy_key(psa_key_id_t id) = 0;
     virtual psa_status_t import_key(const psa_key_attributes_t *attributes,
                             const uint8_t *data, size_t data_length, psa_key_id_t *id) = 0;
@@ -39,7 +40,8 @@
     /* Sign/verify methods */
     virtual psa_status_t sign_hash(psa_key_id_t id, psa_algorithm_t alg,
                             const uint8_t *hash, size_t hash_length,
-                            uint8_t *signature, size_t signature_size, size_t *signature_length) = 0;
+                            uint8_t *signature, size_t signature_size,
+                            size_t *signature_length) = 0;
     virtual psa_status_t verify_hash(psa_key_id_t id, psa_algorithm_t alg,
                             const uint8_t *hash, size_t hash_length,
                             const uint8_t *signature, size_t signature_length) = 0;
@@ -57,6 +59,14 @@
     /* Random number generation */
     virtual psa_status_t generate_random(uint8_t *output, size_t output_size) = 0;
 
+    /* Hash methods */
+    virtual psa_status_t hash_setup(uint32_t *op_handle,
+                            psa_algorithm_t alg) = 0;
+    virtual psa_status_t hash_update(uint32_t op_handle,
+                            const uint8_t *input, size_t input_length) = 0;
+    virtual psa_status_t hash_finish(uint32_t op_handle,
+                            uint8_t *hash, size_t hash_size, size_t *hash_length) = 0;
+
 protected:
     crypto_client();
     crypto_client(struct rpc_caller *caller);
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
index 3685219..a7618ba 100644
--- a/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.cpp
@@ -20,18 +20,19 @@
 #include <protocols/service/crypto/packed-c/import_key.h>
 #include <protocols/service/crypto/packed-c/sign_hash.h>
 #include <protocols/service/crypto/packed-c/verify_hash.h>
+#include <protocols/service/crypto/packed-c/hash.h>
 #include <common/tlv/tlv.h>
 #include <rpc_caller.h>
 
 
 packedc_crypto_client::packedc_crypto_client() :
-    crypto_client()
+	crypto_client()
 {
 
 }
 
 packedc_crypto_client::packedc_crypto_client(struct rpc_caller *caller) :
-    crypto_client(caller)
+	crypto_client(caller)
 {
 
 }
@@ -43,632 +44,798 @@
 
 psa_status_t packedc_crypto_client::generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id)
 {
-    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);
+	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);
+	translate_key_attributes(req_msg.attributes, *attributes);
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
 
-        memcpy(req_buf, &req_msg, req_len);
+		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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			if (psa_status == PSA_SUCCESS) {
 
-                if (resp_len >= sizeof(ts_crypto_generate_key_out)) {
+				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));
-                    *id = resp_msg.id;
-                }
-                else {
-                    /* Failed to decode response message */
-                    psa_status = PSA_ERROR_GENERIC_ERROR;
-                }
-            }
-        }
+					struct ts_crypto_generate_key_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_generate_key_out));
+					*id = resp_msg.id;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
 
-        rpc_caller_end(m_caller, call_handle);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::destroy_key(psa_key_id_t id)
 {
-    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);
+	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.id = id;
+	req_msg.id = id;
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
 
-        memcpy(req_buf, &req_msg, req_len);
+		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);
+		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;
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
 
-        rpc_caller_end(m_caller, call_handle);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	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_id_t *id)
+						const uint8_t *data, size_t data_length, psa_key_id_t *id)
 {
-    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);
+	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);
+	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;
+	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;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
-        struct tlv_iterator req_iter;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
 
-        memcpy(req_buf, &req_msg, req_fixed_len);
+		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);
+		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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			if (psa_status == PSA_SUCCESS) {
 
-                if (resp_len >= sizeof(ts_crypto_import_key_out)) {
+				if (resp_len >= sizeof(ts_crypto_import_key_out)) {
 
-                    struct ts_crypto_import_key_out resp_msg;
-                    memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_import_key_out));
-                    *id = resp_msg.id;
-                }
-                else {
-                    /* Failed to decode response message */
-                    psa_status = PSA_ERROR_GENERIC_ERROR;
-                }
-            }
-        }
+					struct ts_crypto_import_key_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_import_key_out));
+					*id = resp_msg.id;
+				}
+				else {
+					/* Failed to decode response message */
+					psa_status = PSA_ERROR_GENERIC_ERROR;
+				}
+			}
+		}
 
-        rpc_caller_end(m_caller, call_handle);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::export_key(psa_key_id_t id,
-                        uint8_t *data, size_t data_size,
-                        size_t *data_length)
+						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);
+	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.id = id;
+	req_msg.id = id;
 
-    *data_length = 0; /* For failure case */
+	*data_length = 0; /* For failure case */
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
 
-        memcpy(req_buf, &req_msg, req_len);
+		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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_EXPORT_KEY_OUT_TAG_DATA, &decoded_record)) {
 
-                    if (decoded_record.length <= data_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::export_public_key(psa_key_id_t id,
-                                uint8_t *data, size_t data_size, size_t *data_length)
+								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);
+	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.id = id;
+	req_msg.id = id;
 
-    *data_length = 0; /* For failure case */
+	*data_length = 0; /* For failure case */
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
 
-        memcpy(req_buf, &req_msg, req_len);
+		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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_EXPORT_PUBLIC_KEY_OUT_TAG_DATA, &decoded_record)) {
 
-                    if (decoded_record.length <= data_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            uint8_t *signature, size_t signature_size, size_t *signature_length)
+							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);
+	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 */
+	*signature_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	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;
+	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;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
-        struct tlv_iterator req_iter;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
 
-        memcpy(req_buf, &req_msg, req_fixed_len);
+		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_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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_SIGN_HASH_OUT_TAG_SIGNATURE, &decoded_record)) {
 
-                    if (decoded_record.length <= signature_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 
 psa_status_t packedc_crypto_client::verify_hash(psa_key_id_t id, psa_algorithm_t alg,
-                        const uint8_t *hash, size_t hash_length,
-                        const uint8_t *signature, size_t signature_length)
+						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);
+	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.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	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 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;
+	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;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
-        struct tlv_iterator req_iter;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
 
-        memcpy(req_buf, &req_msg, req_fixed_len);
+		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);
+		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);
+		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;
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
 
-        rpc_caller_end(m_caller, call_handle);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::asymmetric_encrypt(psa_key_id_t id, 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)
+						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;
+	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;
 
-    *output_length = 0;  /* For failure case */
+	*output_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	req_msg.alg = alg;
 
-    /* Mandatory parameter */
-    struct tlv_record plaintext_record;
-    plaintext_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT;
-    plaintext_record.length = input_length;
-    plaintext_record.value = input;
-    req_len += tlv_required_space(plaintext_record.length);
+	/* Mandatory parameter */
+	struct tlv_record plaintext_record;
+	plaintext_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_PLAINTEXT;
+	plaintext_record.length = input_length;
+	plaintext_record.value = input;
+	req_len += tlv_required_space(plaintext_record.length);
 
-    /* Optional parameter */
-    struct tlv_record salt_record;
-    salt_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT;
-    salt_record.length = (salt) ? salt_length : 0;
-    salt_record.value = salt;
-    if (salt) req_len += tlv_required_space(salt_record.length);
+	/* Optional parameter */
+	struct tlv_record salt_record;
+	salt_record.tag = TS_CRYPTO_ASYMMETRIC_ENCRYPT_IN_TAG_SALT;
+	salt_record.length = (salt) ? salt_length : 0;
+	salt_record.value = salt;
+	if (salt) req_len += tlv_required_space(salt_record.length);
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus = PSA_ERROR_GENERIC_ERROR;
-        struct tlv_iterator req_iter;
+		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);
+		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);
-        if (salt) tlv_encode(&req_iter, &salt_record);
+		tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+		tlv_encode(&req_iter, &plaintext_record);
+		if (salt) 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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_ASYMMETRIC_ENCRYPT_OUT_TAG_CIPHERTEXT, &decoded_record)) {
 
-                    if (decoded_record.length <= output_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t packedc_crypto_client::asymmetric_decrypt(psa_key_id_t id, 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)
+						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;
+	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;
 
-    *output_length = 0;  /* For failure case */
+	*output_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	req_msg.alg = alg;
 
-    /* Mandatory parameter */
-    struct tlv_record ciphertext_record;
-    ciphertext_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT;
-    ciphertext_record.length = input_length;
-    ciphertext_record.value = input;
-    req_len += tlv_required_space(ciphertext_record.length);
+	/* Mandatory parameter */
+	struct tlv_record ciphertext_record;
+	ciphertext_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_CIPHERTEXT;
+	ciphertext_record.length = input_length;
+	ciphertext_record.value = input;
+	req_len += tlv_required_space(ciphertext_record.length);
 
-    /* Optional parameter */
-    struct tlv_record salt_record;
-    salt_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT;
-    salt_record.length = (salt) ? salt_length : 0;
-    salt_record.value = salt;
-    if (salt) req_len += tlv_required_space(salt_record.length);
+	/* Optional parameter */
+	struct tlv_record salt_record;
+	salt_record.tag = TS_CRYPTO_ASYMMETRIC_DECRYPT_IN_TAG_SALT;
+	salt_record.length = (salt) ? salt_length : 0;
+	salt_record.value = salt;
+	if (salt) req_len += tlv_required_space(salt_record.length);
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
-        struct tlv_iterator req_iter;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
+		struct tlv_iterator req_iter;
 
-        memcpy(req_buf, &req_msg, req_fixed_len);
+		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);
-        if (salt) tlv_encode(&req_iter, &salt_record);
+		tlv_iterator_begin(&req_iter, &req_buf[req_fixed_len], req_len - req_fixed_len);
+		tlv_encode(&req_iter, &ciphertext_record);
+		if (salt) 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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_ASYMMETRIC_DECRYPT_OUT_TAG_PLAINTEXT, &decoded_record)) {
 
-                    if (decoded_record.length <= output_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	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);
+	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;
+	req_msg.size = output_size;
 
-    rpc_call_handle call_handle;
-    uint8_t *req_buf;
+	rpc_call_handle call_handle;
+	uint8_t *req_buf;
 
-    call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+	call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-    if (call_handle) {
+	if (call_handle) {
 
-        uint8_t *resp_buf;
-        size_t resp_len;
-        int opstatus;
+		uint8_t *resp_buf;
+		size_t resp_len;
+		int opstatus;
 
-        memcpy(req_buf, &req_msg, req_len);
+		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);
+		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) {
+		if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-            psa_status = opstatus;
+			psa_status = opstatus;
 
-            if (psa_status == PSA_SUCCESS) {
+			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);
+				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 (tlv_find_decode(&resp_iter,
+					TS_CRYPTO_GENERATE_RANDOM_OUT_TAG_RANDOM_BYTES, &decoded_record)) {
 
-                    if (decoded_record.length <= output_size) {
+					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;
-                }
-            }
-        }
+						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);
-    }
+		rpc_caller_end(m_caller, call_handle);
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
-void packedc_crypto_client::translate_key_attributes(struct ts_crypto_key_attributes &proto_attributes,
-                            const psa_key_attributes_t &psa_attributes)
+psa_status_t packedc_crypto_client::hash_setup(uint32_t *op_handle,
+	psa_algorithm_t alg)
 {
-    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);
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_hash_setup_in req_msg;
+	size_t req_len = sizeof(ts_crypto_hash_setup_in);
 
-    proto_attributes.policy.usage = psa_get_key_usage_flags(&psa_attributes);
-    proto_attributes.policy.alg = psa_get_key_algorithm(&psa_attributes);
+	req_msg.alg = alg;
+
+	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_HASH_SETUP, &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_hash_setup_out)) {
+
+					struct ts_crypto_hash_setup_out resp_msg;
+					memcpy(&resp_msg, resp_buf, sizeof(ts_crypto_hash_setup_out));
+					*op_handle = resp_msg.op_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::hash_update(uint32_t op_handle,
+	const uint8_t *input, size_t input_length)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_hash_update_in req_msg;
+	size_t req_fixed_len = sizeof(ts_crypto_hash_update_in);
+	size_t req_len = req_fixed_len;
+
+	req_msg.op_handle = op_handle;
+
+	/* Mandatory input data parameter */
+	struct tlv_record data_record;
+	data_record.tag = TS_CRYPTO_HASH_UPDATE_IN_TAG_DATA;
+	data_record.length = input_length;
+	data_record.value = input;
+	req_len += tlv_required_space(data_record.length);
+
+	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, &data_record);
+
+		m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+					TS_CRYPTO_OPCODE_HASH_UPDATE, &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::hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length)
+{
+	psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
+	struct ts_crypto_hash_finish_in req_msg;
+	size_t req_fixed_len = sizeof(ts_crypto_hash_finish_in);
+	size_t req_len = req_fixed_len;
+
+	*hash_length = 0;
+	req_msg.op_handle = op_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_fixed_len);
+
+		m_err_rpc_status = rpc_caller_invoke(m_caller, call_handle,
+					TS_CRYPTO_OPCODE_HASH_FINISH, &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_HASH_FINISH_OUT_TAG_HASH, &decoded_record)) {
+
+					if (decoded_record.length <= hash_size) {
+
+						memcpy(hash, decoded_record.value, decoded_record.length);
+						*hash_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;
+}
+
+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
index f3e002b..be4bb66 100644
--- a/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.h
+++ b/components/service/crypto/client/cpp/packed-c/packedc_crypto_client.h
@@ -16,48 +16,56 @@
 class packedc_crypto_client : public crypto_client
 {
 public:
-    packedc_crypto_client();
-    packedc_crypto_client(struct rpc_caller *caller);
-    virtual ~packedc_crypto_client();
+	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_id_t *id);
-    psa_status_t destroy_key(psa_key_id_t id);
-    psa_status_t import_key(const psa_key_attributes_t *attributes,
-                            const uint8_t *data, size_t data_length, psa_key_id_t *id);
+	/* Key lifecycle methods */
+	psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id);
+	psa_status_t destroy_key(psa_key_id_t id);
+	psa_status_t import_key(const psa_key_attributes_t *attributes,
+							const uint8_t *data, size_t data_length, psa_key_id_t *id);
 
-    /* Key export methods */
-    psa_status_t export_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size,
-                            size_t *data_length);
-    psa_status_t export_public_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size, size_t *data_length);
+	/* Key export methods */
+	psa_status_t export_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size,
+							size_t *data_length);
+	psa_status_t export_public_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size, size_t *data_length);
 
-    /* Sign/verify methods */
-    psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            const uint8_t *signature, size_t signature_length);
+	/* Sign/verify methods */
+	psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, 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_id_t id, 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_id_t id, 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);
+	/* Asymmetric encrypt/decrypt */
+	psa_status_t asymmetric_encrypt(psa_key_id_t id, 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_id_t id, 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);
+	/* Random number generation */
+	psa_status_t generate_random(uint8_t *output, size_t output_size);
+
+	/* Hash methods */
+	psa_status_t hash_setup(uint32_t *op_handle,
+							psa_algorithm_t alg);
+	psa_status_t hash_update(uint32_t op_handle,
+							const uint8_t *input, size_t input_length);
+	psa_status_t hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length);
 
 private:
 
-    void translate_key_attributes(struct ts_crypto_key_attributes &proto_attributes,
-                            const psa_key_attributes_t &psa_attributes);
+	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/protobuf_crypto_client.cpp b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp
index 542d0fe..32acd4c 100644
--- a/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp
+++ b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.cpp
@@ -25,13 +25,13 @@
 #include <pb_decode.h>
 
 protobuf_crypto_client::protobuf_crypto_client() :
-    crypto_client()
+	crypto_client()
 {
 
 }
 
 protobuf_crypto_client::protobuf_crypto_client(struct rpc_caller *caller) :
-    crypto_client(caller)
+	crypto_client(caller)
 {
 
 }
@@ -41,668 +41,702 @@
 
 }
 
-psa_status_t protobuf_crypto_client::generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id)
+psa_status_t protobuf_crypto_client::generate_key(const psa_key_attributes_t *attributes,
+	psa_key_id_t *id)
 {
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_GenerateKeyIn req_msg = ts_crypto_GenerateKeyIn_init_default;
+	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;
+	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)) {
+	if (pb_get_encoded_size(&req_len, ts_crypto_GenerateKeyIn_fields, &req_msg)) {
 
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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);
+					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)) {
+					if (pb_decode(&istream, ts_crypto_GenerateKeyOut_fields, &resp_msg)) {
 
-                        *id = resp_msg.id;
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-                }
-            }
+						*id = resp_msg.id;
+					}
+					else {
+						/* Failed to decode response message */
+						psa_status = PSA_ERROR_GENERIC_ERROR;
+					}
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::destroy_key(psa_key_id_t id)
 {
-    size_t req_len;
-    psa_status_t psa_status = PSA_ERROR_GENERIC_ERROR;
-    ts_crypto_DestroyKeyIn req_msg = ts_crypto_DestroyKeyIn_init_default;
+	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.id = id;
+	req_msg.id = id;
 
-    if (pb_get_encoded_size(&req_len, ts_crypto_DestroyKeyIn_fields, &req_msg)) {
+	if (pb_get_encoded_size(&req_len, ts_crypto_DestroyKeyIn_fields, &req_msg)) {
 
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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;
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    return psa_status;
+	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_id_t *id)
+						const uint8_t *data, size_t data_length, psa_key_id_t *id)
 {
-    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);
+	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);
+	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)) {
+	if (pb_get_encoded_size(&req_len, ts_crypto_ImportKeyIn_fields, &req_msg)) {
 
-        rpc_call_handle call_handle;
-        uint8_t *req_buf;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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);
+					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)) {
+					if (pb_decode(&istream, ts_crypto_ImportKeyOut_fields, &resp_msg)) {
 
-                        *id = resp_msg.id;
-                    }
-                    else {
-                        /* Failed to decode response message */
-                        psa_status = PSA_ERROR_GENERIC_ERROR;
-                    }
-                }
-            }
+						*id = resp_msg.id;
+					}
+					else {
+						/* Failed to decode response message */
+						psa_status = PSA_ERROR_GENERIC_ERROR;
+					}
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    ::free(key_byte_array);
+	::free(key_byte_array);
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::export_key(psa_key_id_t id,
-                        uint8_t *data, size_t data_size,
-                        size_t *data_length)
+						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.id = id;
+	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.id = id;
 
-    *data_length = 0; /* For failure case */
+	*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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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);
+					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) {
+					if (exported_key) {
 
-                        resp_msg.data = pb_in_byte_array(exported_key);
-                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+						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 (pb_decode(&istream, ts_crypto_ExportKeyOut_fields, &resp_msg)) {
 
-                            if (exported_key->size <= data_size) {
+							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;
-                        }
+								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;
-                    }
-                }
-            }
+						::free(exported_key);
+					}
+					else {
+						/* Failed to allocate buffer for exported key */
+						psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
+					}
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::export_public_key(psa_key_id_t id,
-                                uint8_t *data, size_t data_size, size_t *data_length)
+								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.id = id;
+	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.id = id;
 
-    *data_length = 0; /* For failure case */
+	*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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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);
+					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) {
+					if (exported_key) {
 
-                        resp_msg.data = pb_in_byte_array(exported_key);
-                        pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
+						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 (pb_decode(&istream, ts_crypto_ExportPublicKeyOut_fields, &resp_msg)) {
 
-                            if (exported_key->size <= data_size) {
+							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;
-                        }
+								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;
-                    }
-                }
-            }
+						::free(exported_key);
+					}
+					else {
+						/* Failed to alloocate buffer for exported key */
+						psa_status = PSA_ERROR_INSUFFICIENT_MEMORY;
+					}
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::sign_hash(psa_key_id_t id, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            uint8_t *signature, size_t signature_size, size_t *signature_length)
+							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;
+	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 */
+	*signature_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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_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);
+					pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
 
-                    if (pb_decode(&istream, ts_crypto_SignHashOut_fields, &resp_msg)) {
+					if (pb_decode(&istream, ts_crypto_SignHashOut_fields, &resp_msg)) {
 
-                        if (sig_byte_array->size <= signature_size) {
+						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;
-                    }
+							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);
-                }
-            }
+					::free(sig_byte_array);
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    ::free(hash_byte_array);
+	::free(hash_byte_array);
 
-    return psa_status;
+	return psa_status;
 }
 
 
 psa_status_t protobuf_crypto_client::verify_hash(psa_key_id_t id, psa_algorithm_t alg,
-                        const uint8_t *hash, size_t hash_length,
-                        const uint8_t *signature, size_t signature_length)
+						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;
+	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.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	req_msg.alg = alg;
 	req_msg.hash = pb_out_byte_array(hash_byte_array);
-    req_msg.signature = pb_out_byte_array(sig_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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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;
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) psa_status = opstatus;
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    ::free(hash_byte_array);
-    ::free(sig_byte_array);
+	::free(hash_byte_array);
+	::free(sig_byte_array);
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::asymmetric_encrypt(psa_key_id_t id, 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)
+						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;
+	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 */
+	*output_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	req_msg.alg = alg;
 	req_msg.plaintext = pb_out_byte_array(plaintext_byte_array);
-    req_msg.salt = pb_out_byte_array(salt_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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus = PSA_ERROR_GENERIC_ERROR;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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_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);
+					pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
 
-                    if (pb_decode(&istream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
+					if (pb_decode(&istream, ts_crypto_AsymmetricEncryptOut_fields, &resp_msg)) {
 
-                        if (ciphertext_byte_array->size <= output_size) {
+						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;
-                    }
+							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);
-                }
-            }
+					::free(ciphertext_byte_array);
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    ::free(plaintext_byte_array);
-    ::free(salt_byte_array);
+	::free(plaintext_byte_array);
+	::free(salt_byte_array);
 
-    return psa_status;
+	return psa_status;
 }
 
 psa_status_t protobuf_crypto_client::asymmetric_decrypt(psa_key_id_t id, 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)
+						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;
+	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 */
+	*output_length = 0;  /* For failure case */
 
-    req_msg.id = id;
-    req_msg.alg = alg;
+	req_msg.id = id;
+	req_msg.alg = alg;
 	req_msg.ciphertext = pb_out_byte_array(ciphertext_byte_array);
-    req_msg.salt = pb_out_byte_array(salt_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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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_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);
+					pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
 
-                    if (pb_decode(&istream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
+					if (pb_decode(&istream, ts_crypto_AsymmetricDecryptOut_fields, &resp_msg)) {
 
-                        if (plaintext_byte_array->size <= output_size) {
+						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;
-                    }
+							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);
-                }
-            }
+					::free(plaintext_byte_array);
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    ::free(ciphertext_byte_array);
-    ::free(salt_byte_array);
+	::free(ciphertext_byte_array);
+	::free(salt_byte_array);
 
-    return psa_status;
+	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;
+	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;
+	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;
+		rpc_call_handle call_handle;
+		uint8_t *req_buf;
 
-        call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
+		call_handle = rpc_caller_begin(m_caller, &req_buf, req_len);
 
-        if (call_handle) {
+		if (call_handle) {
 
-            uint8_t *resp_buf;
-            size_t resp_len;
-            int opstatus;
+			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);
+			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);
+			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) {
+			if (m_err_rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status = opstatus;
+				psa_status = opstatus;
 
-                if (psa_status == PSA_SUCCESS) {
+				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_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);
+					pb_istream_t istream = pb_istream_from_buffer(resp_buf, resp_len);
 
-                    if (pb_decode(&istream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
+					if (pb_decode(&istream, ts_crypto_GenerateRandomOut_fields, &resp_msg)) {
 
-                        if (output_byte_array->size == output_size) {
+						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;
-                    }
+							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);
-                }
-            }
+					::free(output_byte_array);
+				}
+			}
 
-            rpc_caller_end(m_caller, call_handle);
-        }
-    }
+			rpc_caller_end(m_caller, call_handle);
+		}
+	}
 
-    return psa_status;
+	return psa_status;
+}
+
+psa_status_t protobuf_crypto_client::hash_setup(uint32_t *op_handle,
+							psa_algorithm_t alg)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::hash_update(uint32_t op_handle,
+							const uint8_t *input, size_t input_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t protobuf_crypto_client::hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
 }
 
 void protobuf_crypto_client::translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
-                            const psa_key_attributes_t &psa_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.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);
+	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
index 0ada2ca..bc407d1 100644
--- a/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.h
+++ b/components/service/crypto/client/cpp/protobuf/protobuf_crypto_client.h
@@ -16,48 +16,56 @@
 class protobuf_crypto_client : public crypto_client
 {
 public:
-    protobuf_crypto_client();
-    protobuf_crypto_client(struct rpc_caller *caller);
-    virtual ~protobuf_crypto_client();
+	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_id_t *id);
-    psa_status_t destroy_key(psa_key_id_t id);
-    psa_status_t import_key(const psa_key_attributes_t *attributes,
-                            const uint8_t *data, size_t data_length, psa_key_id_t *id);
+	/* Key lifecycle methods */
+	psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id);
+	psa_status_t destroy_key(psa_key_id_t id);
+	psa_status_t import_key(const psa_key_attributes_t *attributes,
+							const uint8_t *data, size_t data_length, psa_key_id_t *id);
 
-    /* Key export methods */
-    psa_status_t export_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size,
-                            size_t *data_length);
-    psa_status_t export_public_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size, size_t *data_length);
+	/* Key export methods */
+	psa_status_t export_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size,
+							size_t *data_length);
+	psa_status_t export_public_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size, size_t *data_length);
 
-    /* Sign/verify methods */
-    psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            const uint8_t *signature, size_t signature_length);
+	/* Sign/verify methods */
+	psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, 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_id_t id, 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_id_t id, 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);
+	/* Asymmetric encrypt/decrypt */
+	psa_status_t asymmetric_encrypt(psa_key_id_t id, 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_id_t id, 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);
+	/* Random number generation */
+	psa_status_t generate_random(uint8_t *output, size_t output_size);
+
+	/* Hash methods */
+	psa_status_t hash_setup(uint32_t *op_handle,
+							psa_algorithm_t alg);
+	psa_status_t hash_update(uint32_t op_handle,
+							const uint8_t *input, size_t input_length);
+	psa_status_t hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length);
 
 private:
 
-    void translate_key_attributes(ts_crypto_KeyAttributes &proto_attributes,
-                            const psa_key_attributes_t &psa_attributes);
+	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/provider/mbedcrypto/component.cmake b/components/service/crypto/provider/mbedcrypto/component.cmake
index 0df1138..6413cb9 100644
--- a/components/service/crypto/provider/mbedcrypto/component.cmake
+++ b/components/service/crypto/provider/mbedcrypto/component.cmake
@@ -10,6 +10,7 @@
 
 target_sources(${TGT} PRIVATE
 	"${CMAKE_CURRENT_LIST_DIR}/crypto_provider.c"
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_context_pool.c"
 	)
 
 target_include_directories(${TGT}
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c
new file mode 100644
index 0000000..753cb9f
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include "crypto_context_pool.h"
+
+static void add_to_free_list(struct crypto_context_pool *pool,
+	struct crypto_context *context);
+
+static uint32_t alloc_op_handle(struct crypto_context_pool *pool);
+static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate);
+
+
+void crypto_context_pool_init(struct crypto_context_pool *pool)
+{
+	pool->free = NULL;
+	pool->active_head = NULL;
+	pool->active_tail = NULL;
+	pool->most_recent_op_handle = 0;
+
+	for (size_t i = 0; i < CRYPTO_CONTEXT_POOL_SIZE; i++) {
+
+		add_to_free_list(pool, &pool->contexts[i]);
+	}
+}
+
+void crypto_context_pool_deinit(struct crypto_context_pool *pool)
+{
+	(void)pool;
+}
+
+struct crypto_context *crypto_context_pool_alloc(struct crypto_context_pool *pool,
+	enum crypto_context_op_id usage,
+	uint32_t client_id,
+	uint32_t *op_handle)
+{
+	struct crypto_context *context = NULL;
+
+	/* Re-cycle least-recently used context if there are no free contexts */
+	if (!pool->free && pool->active_tail) crypto_context_pool_free(pool, pool->active_tail);
+
+	/* Active context are held in a linked list in most recently allocated order */
+	if (pool->free) {
+
+		context = pool->free;
+		pool->free = context->next;
+
+		context->next = pool->active_head;
+		context->prev = NULL;
+		pool->active_head = context;
+
+		if (!pool->active_tail) pool->active_tail = context;
+		if (context->next) context->next->prev = context;
+
+		context->usage = usage;
+		context->client_id = client_id;
+
+		context->op_handle = alloc_op_handle(pool);
+		*op_handle = context->op_handle;
+	}
+
+	return context;
+}
+
+void crypto_context_pool_free(struct crypto_context_pool *pool,
+	struct crypto_context *context)
+{
+	/* Remove from active list */
+	if (context->prev) {
+		context->prev->next = context->next;
+	}
+	else {
+		pool->active_head = context->next;
+	}
+
+	if (context->next) {
+		context->next->prev = context->prev;
+	}
+	else {
+		pool->active_tail = context->prev;
+	}
+
+	/* Add to free list */
+	add_to_free_list(pool, context);
+}
+
+struct crypto_context *crypto_context_pool_find(struct crypto_context_pool *pool,
+	enum crypto_context_op_id usage,
+	uint32_t client_id,
+	uint32_t op_handle)
+{
+	/* Finds an active context that looks as though it legitimately belongs to the
+	 * requesting client.  Defends against bad behaviour from the client such
+	 * as misusing a context for a different operation from the one that was
+	 * setup.
+	 */
+	struct crypto_context *found = NULL;
+	struct crypto_context *context = pool->active_head;
+
+	while (context) {
+
+		if ((context->op_handle == op_handle) &&
+			(context->usage == usage) &&
+			(context->client_id == client_id)) {
+
+			found = context;
+			break;
+		}
+
+		context = context->next;
+	}
+
+	return found;
+}
+
+static void add_to_free_list(struct crypto_context_pool *pool,
+	struct crypto_context *context)
+{
+	context->usage = CRYPTO_CONTEXT_OP_ID_NONE;
+	context->op_handle = 0;
+	context->next = pool->free;
+	context->prev = NULL;
+	pool->free = context;
+}
+
+static uint32_t alloc_op_handle(struct crypto_context_pool *pool)
+{
+	/* op handles need to be unique and to minimize the probability
+	 * of a client using a stale handle that collides with a legitmately
+	 * active one, use a rolling 32-bit integer.
+	 */
+	uint32_t candidate = pool->most_recent_op_handle + 1;
+
+	while (op_handle_in_use(pool, candidate)) ++candidate;
+
+	pool->most_recent_op_handle = candidate;
+
+	return candidate;
+}
+
+static bool op_handle_in_use(struct crypto_context_pool *pool, uint32_t candidate)
+{
+	bool in_use = false;
+	struct crypto_context *context = pool->active_head;
+
+	while (context && !in_use) {
+
+		in_use = (candidate == context->op_handle);
+		context = context->next;
+	}
+
+	return in_use;
+}
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h
new file mode 100644
index 0000000..8d7e564
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/crypto_context_pool.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CRYPTO_CONTEXT_POOL_H
+#define CRYPTO_CONTEXT_POOL_H
+
+#include <stdint.h>
+#include <psa/crypto.h>
+
+/**
+ * Some crypto transactions require state to be held between separate
+ * service operations.  A typical multi-call transaction such as a
+ * hash calculation comprises a setup, one or more updates and a finish
+ * operation.  This pool is used for allocating state context for multi-call
+ * transactions.  For a well behaved client, a fresh context is allocated
+ * on a setup and freed on the finish.  To cope with badly behaved clients
+ * that may never finish a transaction, if no free contexts are available
+ * for a new transaction, the least recently used active context is
+ * recycled.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *  Identifier for the operation type that a context is used for.
+ */
+enum crypto_context_op_id
+{
+	CRYPTO_CONTEXT_OP_ID_NONE,
+	CRYPTO_CONTEXT_OP_ID_HASH,
+	CRYPTO_CONTEXT_OP_ID_MAC,
+	CRYPTO_CONTEXT_OP_ID_CIPHER
+};
+
+/**
+ * A crypto context, used to hold state for a multi-step transaction.
+ */
+struct crypto_context
+{
+	enum crypto_context_op_id usage;
+	uint32_t client_id;
+	uint32_t op_handle;
+	struct crypto_context *next;
+	struct crypto_context *prev;
+
+	union context_variant
+	{
+		struct psa_hash_operation_s hash;
+		struct psa_mac_operation_s mac;
+		struct psa_cipher_operation_s cipher;
+	} op;
+};
+
+/**
+ * The default pool size.  This may be overridden to meet the needs
+ * of a particular deployment.
+ */
+#ifndef CRYPTO_CONTEXT_POOL_SIZE
+#define CRYPTO_CONTEXT_POOL_SIZE            (10)
+#endif
+
+/**
+ * The crypto context pool structure.
+ */
+struct crypto_context_pool
+{
+	struct crypto_context contexts[CRYPTO_CONTEXT_POOL_SIZE];
+	struct crypto_context *free;
+	struct crypto_context *active_head;
+	struct crypto_context *active_tail;
+	uint32_t most_recent_op_handle;
+};
+
+/*
+ * Initializes a crypto_context_pool, called once during setup.
+ */
+void crypto_context_pool_init(struct crypto_context_pool *pool);
+
+/*
+ * De-initializes a crypto_context_pool, called once during tear-down.
+ */
+void crypto_context_pool_deinit(struct crypto_context_pool *pool);
+
+/*
+ * Allocate a fresh context.  On success, a pointer to a crypto_context object
+ * is returned and an op handle is provided for reacqiring the context during
+ * sunsequent operations.
+ */
+struct crypto_context *crypto_context_pool_alloc(struct crypto_context_pool *pool,
+	enum crypto_context_op_id usage,
+	uint32_t client_id,
+	uint32_t *op_handle);
+
+/*
+ * Frees a context after use.
+ */
+void crypto_context_pool_free(struct crypto_context_pool *pool,
+	struct crypto_context *context);
+
+/*
+ * Find an allocated context.  Returns NULL is no qualifying context is held.
+ */
+struct crypto_context *crypto_context_pool_find(struct crypto_context_pool *pool,
+	enum crypto_context_op_id usage,
+	uint32_t client_id,
+	uint32_t op_handle);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* CRYPTO_CONTEXT_POOL_H */
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_provider.c b/components/service/crypto/provider/mbedcrypto/crypto_provider.c
index 1b2fffd..292c180 100644
--- a/components/service/crypto/provider/mbedcrypto/crypto_provider.c
+++ b/components/service/crypto/provider/mbedcrypto/crypto_provider.c
@@ -24,559 +24,697 @@
 static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req);
 static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req);
 static rpc_status_t generate_random_handler(void *context, struct call_req* req);
+static rpc_status_t hash_setup_handler(void *context, struct call_req* req);
+static rpc_status_t hash_update_handler(void *context, struct call_req* req);
+static rpc_status_t hash_finish_handler(void *context, struct call_req* req);
 
 /* Handler mapping table for service */
 static const struct service_handler handler_table[] = {
-    {TS_CRYPTO_OPCODE_NOP,                  nop_handler},
-    {TS_CRYPTO_OPCODE_GENERATE_KEY,         generate_key_handler},
-    {TS_CRYPTO_OPCODE_DESTROY_KEY,          destroy_key_handler},
-    {TS_CRYPTO_OPCODE_EXPORT_KEY,           export_key_handler},
-    {TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY,    export_public_key_handler},
-    {TS_CRYPTO_OPCODE_IMPORT_KEY,           import_key_handler},
-    {TS_CRYPTO_OPCODE_SIGN_HASH,            sign_hash_handler},
-    {TS_CRYPTO_OPCODE_VERIFY_HASH,          verify_hash_handler},
-    {TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT,   asymmetric_decrypt_handler},
-    {TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT,   asymmetric_encrypt_handler},
-    {TS_CRYPTO_OPCODE_GENERATE_RANDOM,      generate_random_handler}
+	{TS_CRYPTO_OPCODE_NOP,                  nop_handler},
+	{TS_CRYPTO_OPCODE_GENERATE_KEY,         generate_key_handler},
+	{TS_CRYPTO_OPCODE_DESTROY_KEY,          destroy_key_handler},
+	{TS_CRYPTO_OPCODE_EXPORT_KEY,           export_key_handler},
+	{TS_CRYPTO_OPCODE_EXPORT_PUBLIC_KEY,    export_public_key_handler},
+	{TS_CRYPTO_OPCODE_IMPORT_KEY,           import_key_handler},
+	{TS_CRYPTO_OPCODE_SIGN_HASH,            sign_hash_handler},
+	{TS_CRYPTO_OPCODE_VERIFY_HASH,          verify_hash_handler},
+	{TS_CRYPTO_OPCODE_ASYMMETRIC_DECRYPT,   asymmetric_decrypt_handler},
+	{TS_CRYPTO_OPCODE_ASYMMETRIC_ENCRYPT,   asymmetric_encrypt_handler},
+	{TS_CRYPTO_OPCODE_GENERATE_RANDOM,      generate_random_handler},
+	{TS_CRYPTO_OPCODE_HASH_SETUP,           hash_setup_handler},
+	{TS_CRYPTO_OPCODE_HASH_UPDATE,          hash_update_handler},
+	{TS_CRYPTO_OPCODE_HASH_FINISH,          hash_finish_handler}
 };
 
 struct rpc_interface *mbed_crypto_provider_init(struct mbed_crypto_provider *context,
-                                        struct storage_backend *storage_backend,
-                                        int trng_instance)
+										struct storage_backend *storage_backend,
+										int trng_instance)
 {
-    struct rpc_interface *rpc_interface = NULL;
+	struct rpc_interface *rpc_interface = NULL;
 
-    trng_adapter_init(trng_instance);
+	crypto_context_pool_init(&context->context_pool);
+	trng_adapter_init(trng_instance);
 
-    /*
-     * A storage provider is required for persistent key storage.  As this
-     * is a mandatory feature of the crypto service, insist on a storage
-     * provider being available.
-     */
-    if (context && storage_backend) {
+	/*
+	 * A storage provider is required for persistent key storage.  As this
+	 * is a mandatory feature of the crypto service, insist on a storage
+	 * provider being available.
+	 */
+	if (context && storage_backend) {
 
-        for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
-            context->serializers[encoding] = NULL;
+		for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
+			context->serializers[encoding] = NULL;
 
-        service_provider_init(&context->base_provider, context,
-                    handler_table, sizeof(handler_table)/sizeof(struct service_handler));
+		service_provider_init(&context->base_provider, context,
+					handler_table, sizeof(handler_table)/sizeof(struct service_handler));
 
-        if ((psa_its_frontend_init(storage_backend) == PSA_SUCCESS) &&
-            (psa_crypto_init() == PSA_SUCCESS)) {
+		if ((psa_its_frontend_init(storage_backend) == PSA_SUCCESS) &&
+			(psa_crypto_init() == PSA_SUCCESS)) {
 
-            rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
-        }
-    }
+			rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
+		}
+	}
 
-    return rpc_interface;
+	return rpc_interface;
 }
 
 void mbed_crypto_provider_deinit(struct mbed_crypto_provider *context)
 {
-    (void)context;
-    trng_adapter_deinit();
+	trng_adapter_deinit();
+	crypto_context_pool_deinit(&context->context_pool);
 }
 
 void mbed_crypto_provider_register_serializer(struct mbed_crypto_provider *context,
-                        unsigned int encoding, const struct crypto_provider_serializer *serializer)
+						unsigned int encoding, const struct crypto_provider_serializer *serializer)
 {
-    if (encoding < TS_RPC_ENCODING_LIMIT)
-        context->serializers[encoding] = serializer;
+	if (encoding < TS_RPC_ENCODING_LIMIT)
+		context->serializers[encoding] = serializer;
 }
 
 static const struct crypto_provider_serializer* get_crypto_serializer(void *context,
-                                                        const struct call_req *req)
+														const struct call_req *req)
 {
-    struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
-    const struct crypto_provider_serializer* serializer = NULL;
-    unsigned int encoding = call_req_get_encoding(req);
+	struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+	const struct crypto_provider_serializer* serializer = NULL;
+	unsigned int encoding = call_req_get_encoding(req);
 
-    if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+	if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
 
-    return serializer;
+	return serializer;
 }
 
 static rpc_status_t nop_handler(void *context, struct call_req* req)
 {
-    /* Responds to a request by returning success */
-    rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
-    psa_status_t psa_status = PSA_SUCCESS;
+	/* Responds to a request by returning success */
+	rpc_status_t rpc_status = TS_RPC_CALL_ACCEPTED;
+	psa_status_t psa_status = PSA_SUCCESS;
 
-    (void)context;
-    call_req_set_opstatus(req, psa_status);
+	(void)context;
+	call_req_set_opstatus(req, psa_status);
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t generate_key_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-    if (serializer)
-        rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
+	if (serializer)
+		rpc_status = serializer->deserialize_generate_key_req(req_buf, &attributes);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
-        psa_key_id_t id;
+		psa_status_t psa_status;
+		psa_key_id_t id;
 
-        psa_status = psa_generate_key(&attributes, &id);
+		psa_status = psa_generate_key(&attributes, &id);
 
-        if (psa_status == PSA_SUCCESS) {
+		if (psa_status == PSA_SUCCESS) {
 
-            struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-            rpc_status = serializer->serialize_generate_key_resp(resp_buf, id);
-        }
+			struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+			rpc_status = serializer->serialize_generate_key_resp(resp_buf, id);
+		}
 
-        call_req_set_opstatus(req, psa_status);
-    }
+		call_req_set_opstatus(req, psa_status);
+	}
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t destroy_key_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_id_t id;
+	psa_key_id_t id;
 
-    if (serializer)
-        rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
+	if (serializer)
+		rpc_status = serializer->deserialize_destroy_key_req(req_buf, &id);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
+		psa_status_t psa_status;
 
-        psa_status = psa_destroy_key(id);
-        call_req_set_opstatus(req, psa_status);
-    }
+		psa_status = psa_destroy_key(id);
+		call_req_set_opstatus(req, psa_status);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t export_key_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_id_t id;
+	psa_key_id_t id;
 
-    if (serializer)
-        rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
+	if (serializer)
+		rpc_status = serializer->deserialize_export_key_req(req_buf, &id);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+		psa_status_t psa_status;
+		psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-        psa_status = psa_get_key_attributes(id, &attributes);
+		psa_status = psa_get_key_attributes(id, &attributes);
 
-        if (psa_status == PSA_SUCCESS) {
+		if (psa_status == PSA_SUCCESS) {
 
-            size_t max_export_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
-                psa_get_key_type(&attributes),
-                psa_get_key_bits(&attributes));
+			size_t max_export_size = PSA_EXPORT_KEY_OUTPUT_SIZE(
+				psa_get_key_type(&attributes),
+				psa_get_key_bits(&attributes));
 
-            uint8_t *key_buffer = malloc(max_export_size);
+			uint8_t *key_buffer = malloc(max_export_size);
 
-            if (key_buffer) {
+			if (key_buffer) {
 
-                size_t export_size;
-                psa_status = psa_export_key(id, key_buffer, max_export_size, &export_size);
+				size_t export_size;
+				psa_status = psa_export_key(id, key_buffer, max_export_size, &export_size);
 
-                if (psa_status == PSA_SUCCESS) {
+				if (psa_status == PSA_SUCCESS) {
 
-                    struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                    rpc_status = serializer->serialize_export_key_resp(resp_buf, key_buffer, export_size);
-                }
+					struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+					rpc_status = serializer->serialize_export_key_resp(resp_buf, key_buffer, export_size);
+				}
 
-                free(key_buffer);
-            }
-            else {
-                /* Failed to allocate key buffer */
-                rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-            }
-        }
+				free(key_buffer);
+			}
+			else {
+				/* Failed to allocate key buffer */
+				rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+			}
+		}
 
-        call_req_set_opstatus(req, psa_status);
-        psa_reset_key_attributes(&attributes);
-    }
+		call_req_set_opstatus(req, psa_status);
+		psa_reset_key_attributes(&attributes);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t export_public_key_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_id_t id;
+	psa_key_id_t id;
 
-    if (serializer)
-        rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
+	if (serializer)
+		rpc_status = serializer->deserialize_export_public_key_req(req_buf, &id);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
-        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+		psa_status_t psa_status;
+		psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-        psa_status = psa_get_key_attributes(id, &attributes);
+		psa_status = psa_get_key_attributes(id, &attributes);
 
-        if (psa_status == PSA_SUCCESS) {
+		if (psa_status == PSA_SUCCESS) {
 
-            size_t max_export_size = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(
-                PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_get_key_type(&attributes)),
-                psa_get_key_bits(&attributes));
+			size_t max_export_size = PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE(
+				PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(psa_get_key_type(&attributes)),
+				psa_get_key_bits(&attributes));
 
-            uint8_t *key_buffer = malloc(max_export_size);
+			uint8_t *key_buffer = malloc(max_export_size);
 
-            if (key_buffer) {
+			if (key_buffer) {
 
-                size_t export_size;
-                psa_status = psa_export_public_key(id, key_buffer, max_export_size, &export_size);
+				size_t export_size;
+				psa_status = psa_export_public_key(id, key_buffer, max_export_size, &export_size);
 
-                if (psa_status == PSA_SUCCESS) {
+				if (psa_status == PSA_SUCCESS) {
 
-                    struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                    rpc_status = serializer->serialize_export_public_key_resp(resp_buf, key_buffer, export_size);
-                }
+					struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+					rpc_status = serializer->serialize_export_public_key_resp(resp_buf, key_buffer, export_size);
+				}
 
-                free(key_buffer);
-            }
-            else {
-                /* Failed to allocate key buffer */
-                rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-            }
-        }
+				free(key_buffer);
+			}
+			else {
+				/* Failed to allocate key buffer */
+				rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+			}
+		}
 
-        call_req_set_opstatus(req, psa_status);
-        psa_reset_key_attributes(&attributes);
-    }
+		call_req_set_opstatus(req, psa_status);
+		psa_reset_key_attributes(&attributes);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t import_key_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    if (serializer) {
+	if (serializer) {
 
-        size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
-        uint8_t *key_buffer = malloc(key_data_len);
+		size_t key_data_len = serializer->max_deserialised_parameter_size(req_buf);
+		uint8_t *key_buffer = malloc(key_data_len);
 
-        if (key_buffer) {
+		if (key_buffer) {
 
-            psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-            rpc_status = serializer->deserialize_import_key_req(req_buf, &attributes, key_buffer, &key_data_len);
+			psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+			rpc_status = serializer->deserialize_import_key_req(req_buf, &attributes, key_buffer, &key_data_len);
 
-            if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+			if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status_t psa_status;
-                psa_key_id_t id;
+				psa_status_t psa_status;
+				psa_key_id_t id;
 
-                psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
+				psa_status = psa_import_key(&attributes, key_buffer, key_data_len, &id);
 
-                if (psa_status == PSA_SUCCESS) {
+				if (psa_status == PSA_SUCCESS) {
 
-                    struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                    rpc_status = serializer->serialize_import_key_resp(resp_buf, id);
-                }
+					struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+					rpc_status = serializer->serialize_import_key_resp(resp_buf, id);
+				}
 
-                call_req_set_opstatus(req, psa_status);
-            }
+				call_req_set_opstatus(req, psa_status);
+			}
 
-            psa_reset_key_attributes(&attributes);
-            free(key_buffer);
-        }
-        else {
+			psa_reset_key_attributes(&attributes);
+			free(key_buffer);
+		}
+		else {
 
-            rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-        }
-    }
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t sign_hash_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_id_t id;
-    psa_algorithm_t alg;
-    size_t hash_len = PSA_HASH_MAX_SIZE;
-    uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
+	psa_key_id_t id;
+	psa_algorithm_t alg;
+	size_t hash_len = PSA_HASH_MAX_SIZE;
+	uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
 
-    if (serializer)
-        rpc_status = serializer->deserialize_sign_hash_req(req_buf, &id, &alg, hash_buffer, &hash_len);
+	if (serializer)
+		rpc_status = serializer->deserialize_sign_hash_req(req_buf, &id, &alg, hash_buffer, &hash_len);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
-        size_t sig_len;
-        uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
+		psa_status_t psa_status;
+		size_t sig_len;
+		uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
 
-        psa_status = psa_sign_hash(id, alg,
-                    hash_buffer, hash_len,
-                    sig_buffer, sizeof(sig_buffer), &sig_len);
+		psa_status = psa_sign_hash(id, alg,
+					hash_buffer, hash_len,
+					sig_buffer, sizeof(sig_buffer), &sig_len);
 
-        if (psa_status == PSA_SUCCESS) {
+		if (psa_status == PSA_SUCCESS) {
 
-            struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-            rpc_status = serializer->serialize_sign_hash_resp(resp_buf, sig_buffer, sig_len);
-        }
+			struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+			rpc_status = serializer->serialize_sign_hash_resp(resp_buf, sig_buffer, sig_len);
+		}
 
-        call_req_set_opstatus(req, psa_status);
-    }
+		call_req_set_opstatus(req, psa_status);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t verify_hash_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    psa_key_id_t id;
-    psa_algorithm_t alg;
-    size_t hash_len = PSA_HASH_MAX_SIZE;
-    uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
-    size_t sig_len = PSA_SIGNATURE_MAX_SIZE;
-    uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
+	psa_key_id_t id;
+	psa_algorithm_t alg;
+	size_t hash_len = PSA_HASH_MAX_SIZE;
+	uint8_t hash_buffer[PSA_HASH_MAX_SIZE];
+	size_t sig_len = PSA_SIGNATURE_MAX_SIZE;
+	uint8_t sig_buffer[PSA_SIGNATURE_MAX_SIZE];
 
-    if (serializer)
-        rpc_status = serializer->deserialize_verify_hash_req(req_buf, &id, &alg,
-                                            hash_buffer, &hash_len,
-                                            sig_buffer, &sig_len);
+	if (serializer)
+		rpc_status = serializer->deserialize_verify_hash_req(req_buf, &id, &alg,
+											hash_buffer, &hash_len,
+											sig_buffer, &sig_len);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
+		psa_status_t psa_status;
 
-        psa_status = psa_verify_hash(id, alg,
-                    hash_buffer, hash_len,
-                    sig_buffer, sig_len);
+		psa_status = psa_verify_hash(id, alg,
+					hash_buffer, hash_len,
+					sig_buffer, sig_len);
 
-        call_req_set_opstatus(req, psa_status);
-    }
+		call_req_set_opstatus(req, psa_status);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t asymmetric_decrypt_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    if (serializer) {
+	if (serializer) {
 
-        size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
+		size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
 
-        psa_key_id_t id;
-        psa_algorithm_t alg;
-        size_t ciphertext_len = max_param_size;
-        uint8_t *ciphertext_buffer = malloc(ciphertext_len);
-        size_t salt_len = max_param_size;
-        uint8_t *salt_buffer = malloc(salt_len);
+		psa_key_id_t id;
+		psa_algorithm_t alg;
+		size_t ciphertext_len = max_param_size;
+		uint8_t *ciphertext_buffer = malloc(ciphertext_len);
+		size_t salt_len = max_param_size;
+		uint8_t *salt_buffer = malloc(salt_len);
 
-        if (ciphertext_buffer && salt_buffer) {
+		if (ciphertext_buffer && salt_buffer) {
 
-            rpc_status = serializer->deserialize_asymmetric_decrypt_req(req_buf,
-                                                    &id, &alg,
-                                                    ciphertext_buffer, &ciphertext_len,
-                                                    salt_buffer, &salt_len);
+			rpc_status = serializer->deserialize_asymmetric_decrypt_req(req_buf,
+													&id, &alg,
+													ciphertext_buffer, &ciphertext_len,
+													salt_buffer, &salt_len);
 
-            if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+			if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status_t psa_status;
-                psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+				psa_status_t psa_status;
+				psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-                psa_status = psa_get_key_attributes(id, &attributes);
+				psa_status = psa_get_key_attributes(id, &attributes);
 
-                if (psa_status == PSA_SUCCESS) {
+				if (psa_status == PSA_SUCCESS) {
 
-                    size_t max_decrypt_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
-                        psa_get_key_type(&attributes),
-                        psa_get_key_bits(&attributes),
-                        alg);
+					size_t max_decrypt_size = PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(
+						psa_get_key_type(&attributes),
+						psa_get_key_bits(&attributes),
+						alg);
 
-                    size_t plaintext_len;
-                    uint8_t *plaintext_buffer = malloc(max_decrypt_size);
+					size_t plaintext_len;
+					uint8_t *plaintext_buffer = malloc(max_decrypt_size);
 
-                    if (plaintext_buffer) {
+					if (plaintext_buffer) {
 
-                        /* Salt is an optional parameter */
-                        uint8_t *salt = (salt_len) ? salt_buffer : NULL;
+						/* Salt is an optional parameter */
+						uint8_t *salt = (salt_len) ? salt_buffer : NULL;
 
-                        psa_status = psa_asymmetric_decrypt(id, alg,
-                                    ciphertext_buffer, ciphertext_len,
-                                    salt, salt_len,
-                                    plaintext_buffer, max_decrypt_size, &plaintext_len);
+						psa_status = psa_asymmetric_decrypt(id, alg,
+									ciphertext_buffer, ciphertext_len,
+									salt, salt_len,
+									plaintext_buffer, max_decrypt_size, &plaintext_len);
 
-                        if (psa_status == PSA_SUCCESS) {
+						if (psa_status == PSA_SUCCESS) {
 
-                            struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                            rpc_status = serializer->serialize_asymmetric_decrypt_resp(resp_buf,
-                                                                plaintext_buffer, plaintext_len);
-                        }
+							struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+							rpc_status = serializer->serialize_asymmetric_decrypt_resp(resp_buf,
+																plaintext_buffer, plaintext_len);
+						}
 
-                        free(plaintext_buffer);
-                    }
-                    else {
-                        /* Failed to allocate ouptput buffer */
-                        rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-                    }
-                }
+						free(plaintext_buffer);
+					}
+					else {
+						/* Failed to allocate ouptput buffer */
+						rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+					}
+				}
 
-                call_req_set_opstatus(req, psa_status);
-                psa_reset_key_attributes(&attributes);
-            }
-        }
-        else {
-            /* Failed to allocate buffers */
-            rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-        }
+				call_req_set_opstatus(req, psa_status);
+				psa_reset_key_attributes(&attributes);
+			}
+		}
+		else {
+			/* Failed to allocate buffers */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
 
-        free(ciphertext_buffer);
-        free(salt_buffer);
-    }
+		free(ciphertext_buffer);
+		free(salt_buffer);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t asymmetric_encrypt_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    if (serializer) {
+	if (serializer) {
 
-        size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
+		size_t max_param_size = serializer->max_deserialised_parameter_size(req_buf);
 
-        psa_key_id_t id;
-        psa_algorithm_t alg;
-        size_t plaintext_len = max_param_size;
-        uint8_t *plaintext_buffer = malloc(plaintext_len);
-        size_t salt_len = max_param_size;
-        uint8_t *salt_buffer = malloc(salt_len);
+		psa_key_id_t id;
+		psa_algorithm_t alg;
+		size_t plaintext_len = max_param_size;
+		uint8_t *plaintext_buffer = malloc(plaintext_len);
+		size_t salt_len = max_param_size;
+		uint8_t *salt_buffer = malloc(salt_len);
 
-        if (plaintext_buffer && salt_buffer) {
+		if (plaintext_buffer && salt_buffer) {
 
-            rpc_status = serializer->deserialize_asymmetric_encrypt_req(req_buf,
-                                                    &id, &alg,
-                                                    plaintext_buffer, &plaintext_len,
-                                                    salt_buffer, &salt_len);
+			rpc_status = serializer->deserialize_asymmetric_encrypt_req(req_buf,
+													&id, &alg,
+													plaintext_buffer, &plaintext_len,
+													salt_buffer, &salt_len);
 
-            if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+			if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-                psa_status_t psa_status;
-                psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+				psa_status_t psa_status;
+				psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-                psa_status = psa_get_key_attributes(id, &attributes);
+				psa_status = psa_get_key_attributes(id, &attributes);
 
-                if (psa_status == PSA_SUCCESS) {
+				if (psa_status == PSA_SUCCESS) {
 
-                    size_t max_encrypt_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
-                        psa_get_key_type(&attributes),
-                        psa_get_key_bits(&attributes),
-                        alg);
+					size_t max_encrypt_size = PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(
+						psa_get_key_type(&attributes),
+						psa_get_key_bits(&attributes),
+						alg);
 
-                    size_t ciphertext_len;
-                    uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
+					size_t ciphertext_len;
+					uint8_t *ciphertext_buffer = malloc(max_encrypt_size);
 
-                    if (ciphertext_buffer) {
+					if (ciphertext_buffer) {
 
-                        /* Salt is an optional parameter */
-                        uint8_t *salt = (salt_len) ? salt_buffer : NULL;
+						/* Salt is an optional parameter */
+						uint8_t *salt = (salt_len) ? salt_buffer : NULL;
 
-                        psa_status = psa_asymmetric_encrypt(id, alg,
-                                    plaintext_buffer, plaintext_len,
-                                    salt, salt_len,
-                                    ciphertext_buffer, max_encrypt_size, &ciphertext_len);
+						psa_status = psa_asymmetric_encrypt(id, alg,
+									plaintext_buffer, plaintext_len,
+									salt, salt_len,
+									ciphertext_buffer, max_encrypt_size, &ciphertext_len);
 
-                        if (psa_status == PSA_SUCCESS) {
+						if (psa_status == PSA_SUCCESS) {
 
-                            struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                            rpc_status = serializer->serialize_asymmetric_encrypt_resp(resp_buf,
-                                                                ciphertext_buffer, ciphertext_len);
-                        }
+							struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+							rpc_status = serializer->serialize_asymmetric_encrypt_resp(resp_buf,
+																ciphertext_buffer, ciphertext_len);
+						}
 
-                        free(ciphertext_buffer);
-                    }
-                    else {
-                        /* Failed to allocate ouptput buffer */
-                        rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-                    }
-                }
+						free(ciphertext_buffer);
+					}
+					else {
+						/* Failed to allocate ouptput buffer */
+						rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+					}
+				}
 
-                call_req_set_opstatus(req, psa_status);
-                psa_reset_key_attributes(&attributes);
-            }
-        }
-        else {
-            /* Failed to allocate buffers */
-            rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-        }
+				call_req_set_opstatus(req, psa_status);
+				psa_reset_key_attributes(&attributes);
+			}
+		}
+		else {
+			/* Failed to allocate buffers */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
 
-        free(plaintext_buffer);
-        free(salt_buffer);
-    }
+		free(plaintext_buffer);
+		free(salt_buffer);
+	}
 
-    return rpc_status;
+	return rpc_status;
 }
 
 static rpc_status_t generate_random_handler(void *context, struct call_req* req)
 {
-    rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
-    struct call_param_buf *req_buf = call_req_get_req_buf(req);
-    const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
 
-    size_t output_size;
+	size_t output_size;
 
-    if (serializer)
-        rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
+	if (serializer)
+		rpc_status = serializer->deserialize_generate_random_req(req_buf, &output_size);
 
-    if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
 
-        psa_status_t psa_status;
-        uint8_t *output_buffer = malloc(output_size);
+		psa_status_t psa_status;
+		uint8_t *output_buffer = malloc(output_size);
 
-        if (output_buffer) {
+		if (output_buffer) {
 
-            psa_status = psa_generate_random(output_buffer, output_size);
+			psa_status = psa_generate_random(output_buffer, output_size);
 
-            if (psa_status == PSA_SUCCESS) {
+			if (psa_status == PSA_SUCCESS) {
 
-                struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
-                rpc_status = serializer->serialize_generate_random_resp(resp_buf,
-                                                    output_buffer, output_size);
-            }
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_generate_random_resp(resp_buf,
+													output_buffer, output_size);
+			}
 
-            call_req_set_opstatus(req, psa_status);
-            free(output_buffer);
-        }
-        else {
-            /* Failed to allocate output buffer */
-            rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
-        }
-    }
+			call_req_set_opstatus(req, psa_status);
+			free(output_buffer);
+		}
+		else {
+			/* Failed to allocate output buffer */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
 
-    return rpc_status;
+	return rpc_status;
+}
+
+static rpc_status_t hash_setup_handler(void *context, struct call_req* req)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+	psa_algorithm_t alg;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_hash_setup_req(req_buf, &alg);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		uint32_t op_handle;
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_alloc(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+				&op_handle);
+
+		if (crypto_context) {
+
+			psa_status_t psa_status;
+
+			crypto_context->op.hash = psa_hash_operation_init();
+			psa_status = psa_hash_setup(&crypto_context->op.hash, alg);
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_hash_setup_resp(resp_buf, op_handle);
+			}
+
+			if ((psa_status != PSA_SUCCESS) || (rpc_status != TS_RPC_CALL_ACCEPTED)) {
+
+				crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+			}
+
+			call_req_set_opstatus(req, psa_status);
+		}
+		else {
+			/* Failed to allocate crypto context for transaction */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t hash_update_handler(void *context, struct call_req* req)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+	uint32_t op_handle;
+	const uint8_t *data;
+	size_t data_len;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_hash_update_req(req_buf, &op_handle, &data, &data_len);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status_t psa_status = psa_hash_update(&crypto_context->op.hash, data, data_len);
+			call_req_set_opstatus(req, psa_status);
+		}
+		else {
+			/* Requested context doesn't exist */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
+
+	return rpc_status;
+}
+
+static rpc_status_t hash_finish_handler(void *context, struct call_req* req)
+{
+	rpc_status_t rpc_status = TS_RPC_ERROR_SERIALIZATION_NOT_SUPPORTED;
+	struct call_param_buf *req_buf = call_req_get_req_buf(req);
+	const struct crypto_provider_serializer *serializer = get_crypto_serializer(context, req);
+	struct mbed_crypto_provider *this_instance = (struct mbed_crypto_provider*)context;
+
+	uint32_t op_handle;
+
+	if (serializer)
+		rpc_status = serializer->deserialize_hash_finish_req(req_buf, &op_handle);
+
+	if (rpc_status == TS_RPC_CALL_ACCEPTED) {
+
+		struct crypto_context *crypto_context =
+			crypto_context_pool_find(&this_instance->context_pool,
+				CRYPTO_CONTEXT_OP_ID_HASH, call_req_get_caller_id(req),
+				op_handle);
+
+		if (crypto_context) {
+
+			psa_status_t psa_status;
+			size_t hash_len;
+			uint8_t hash[PSA_HASH_MAX_SIZE];
+
+			psa_status = psa_hash_finish(&crypto_context->op.hash, hash, sizeof(hash), &hash_len);
+
+			if (psa_status == PSA_SUCCESS) {
+
+				struct call_param_buf *resp_buf = call_req_get_resp_buf(req);
+				rpc_status = serializer->serialize_hash_finish_resp(resp_buf, hash, hash_len);
+			}
+
+			crypto_context_pool_free(&this_instance->context_pool, crypto_context);
+
+			call_req_set_opstatus(req, psa_status);
+		}
+		else {
+			/* Requested context doesn't exist */
+			rpc_status = TS_RPC_ERROR_RESOURCE_FAILURE;
+		}
+	}
+
+	return rpc_status;
 }
diff --git a/components/service/crypto/provider/mbedcrypto/crypto_provider.h b/components/service/crypto/provider/mbedcrypto/crypto_provider.h
index 3c0f8d8..19bc2c2 100644
--- a/components/service/crypto/provider/mbedcrypto/crypto_provider.h
+++ b/components/service/crypto/provider/mbedcrypto/crypto_provider.h
@@ -12,6 +12,7 @@
 #include <service/crypto/provider/serializer/crypto_provider_serializer.h>
 #include <service/secure_storage/backend/storage_backend.h>
 #include <protocols/rpc/common/packed-c/encoding.h>
+#include "crypto_context_pool.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -20,6 +21,7 @@
 struct mbed_crypto_provider
 {
     struct service_provider base_provider;
+    struct crypto_context_pool context_pool;
     const struct crypto_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
 };
 
diff --git a/components/service/crypto/provider/mbedcrypto/test/component.cmake b/components/service/crypto/provider/mbedcrypto/test/component.cmake
new file mode 100644
index 0000000..4f754a2
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 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_context_pool_tests.cpp"
+	)
diff --git a/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp b/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp
new file mode 100644
index 0000000..1b6a12e
--- /dev/null
+++ b/components/service/crypto/provider/mbedcrypto/test/crypto_context_pool_tests.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+#include <service/crypto/provider/mbedcrypto/crypto_context_pool.h>
+#include <CppUTest/TestHarness.h>
+
+/*
+ * Component tests for the crypto_context_pool.
+ */
+TEST_GROUP(CryptoContextPoolTests)
+{
+	void setup()
+	{
+		crypto_context_pool_init(&pool_under_test);
+	}
+
+	void teardown()
+	{
+		crypto_context_pool_deinit(&pool_under_test);
+	}
+
+	struct crypto_context_pool pool_under_test;
+};
+
+TEST(CryptoContextPoolTests, checkEmptyPool)
+{
+	struct crypto_context *context =
+		crypto_context_pool_find(&pool_under_test, CRYPTO_CONTEXT_OP_ID_HASH, 0, 0);
+
+	/* Expect a freshly initialized pool to fail to find a context */
+	CHECK_FALSE(context);
+}
+
+TEST(CryptoContextPoolTests, singleContext)
+{
+	uint32_t op_handle;
+	uint32_t client_id = 22;
+
+	struct crypto_context *initial_context =
+		crypto_context_pool_alloc(&pool_under_test,
+			CRYPTO_CONTEXT_OP_ID_HASH, client_id,
+			&op_handle);
+
+	CHECK_TRUE(initial_context);
+
+	struct crypto_context *follow_on_context =
+		crypto_context_pool_find(&pool_under_test,
+		CRYPTO_CONTEXT_OP_ID_HASH, client_id,
+		op_handle);
+
+	UNSIGNED_LONGS_EQUAL(initial_context, follow_on_context);
+
+	crypto_context_pool_free(&pool_under_test, initial_context);
+}
+
+TEST(CryptoContextPoolTests, multipleContexts)
+{
+	/* Test multiple concurrent contexts but never exceeding the pool size */
+	struct crypto_context *context;
+	uint32_t zombie_handle_1, zombie_handle_2;
+
+	/* First start a couple of zombie contexts.  This will occur if a client
+	 * starts a transaction but never finishes it.  This could happen due to a
+	 * misbehaving client or if a client process crashes.  This checks that
+	 * recycling of least recently used contexts is working.
+	 */
+	context = crypto_context_pool_alloc(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_MAC, 77,
+				&zombie_handle_1);
+	CHECK_TRUE(context);
+
+	context = crypto_context_pool_alloc(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_CIPHER, 88,
+				&zombie_handle_2);
+	CHECK_TRUE(context);
+
+	/* Now run through the normal life-cycle for a load of concurrent contexts */
+	for (unsigned int i = 0; i < 1000; ++i) {
+
+		uint32_t op_handles[CRYPTO_CONTEXT_POOL_SIZE];
+		unsigned int num_concurrent = (rand() % CRYPTO_CONTEXT_POOL_SIZE) + 1;
+
+		/* Start some concurrent contexts, each belonging to different clients */
+		for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+			context = crypto_context_pool_alloc(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+				&op_handles[context_index]);
+
+			CHECK_TRUE(context);
+		}
+
+		/* Expect the find to work for all active contexts */
+		for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+			context = crypto_context_pool_find(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+				op_handles[context_index]);
+
+			CHECK_TRUE(context);
+		}
+
+		/* Then find and free all contexts */
+		for (unsigned int context_index = 0; context_index < num_concurrent; ++context_index) {
+
+			context = crypto_context_pool_find(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_HASH, context_index,
+				op_handles[context_index]);
+
+			CHECK_TRUE(context);
+
+			crypto_context_pool_free(&pool_under_test, context);
+		}
+	}
+
+	/* Expect the zombie contexts to have been recycled */
+	context = crypto_context_pool_find(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_MAC, 77,
+				zombie_handle_1);
+	CHECK_FALSE(context);
+
+	context = crypto_context_pool_find(&pool_under_test,
+				CRYPTO_CONTEXT_OP_ID_CIPHER, 88,
+				zombie_handle_2);
+	CHECK_FALSE(context);
+}
diff --git a/components/service/crypto/provider/serializer/crypto_provider_serializer.h b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
index 9bcc305..96bee3a 100644
--- a/components/service/crypto/provider/serializer/crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
@@ -97,6 +97,25 @@
 
     rpc_status_t (*serialize_generate_random_resp)(struct call_param_buf *resp_buf,
                                         const uint8_t *output, size_t output_len);
+
+    /* Operation: hash_setup */
+    rpc_status_t (*deserialize_hash_setup_req)(const struct call_param_buf *req_buf,
+                                        psa_algorithm_t *alg);
+
+    rpc_status_t (*serialize_hash_setup_resp)(struct call_param_buf *resp_buf,
+                                        uint32_t op_handle);
+
+    /* Operation: hash_update */
+    rpc_status_t (*deserialize_hash_update_req)(const struct call_param_buf *req_buf,
+                                        uint32_t *op_handle,
+                                        const uint8_t **data, size_t *data_len);
+
+    /* Operation: hash_finish */
+    rpc_status_t (*deserialize_hash_finish_req)(const struct call_param_buf *req_buf,
+                                        uint32_t *op_handle);
+
+    rpc_status_t (*serialize_hash_finish_resp)(struct call_param_buf *resp_buf,
+                                        const uint8_t *hash, size_t hash_len);
 };
 
 #endif /* CRYPTO_PROVIDER_SERIALIZER_H */
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
index e69defb..ffccc73 100644
--- 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
@@ -19,6 +19,7 @@
 #include <protocols/service/crypto/packed-c/import_key.h>
 #include <protocols/service/crypto/packed-c/sign_hash.h>
 #include <protocols/service/crypto/packed-c/verify_hash.h>
+#include <protocols/service/crypto/packed-c/hash.h>
 #include "packedc_crypto_provider_serializer.h"
 #include "packedc_key_attributes_translator.h"
 
@@ -573,6 +574,122 @@
     return rpc_status;
 }
 
+/* Operation: hash_setup */
+static rpc_status_t deserialize_hash_setup_req(const struct call_param_buf *req_buf,
+                                    psa_algorithm_t *alg)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_hash_setup_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_hash_setup_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *alg = recv_msg.alg;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_hash_setup_resp(struct call_param_buf *resp_buf,
+                                    uint32_t op_handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INTERNAL;
+    struct ts_crypto_hash_setup_out resp_msg;
+    size_t fixed_len = sizeof(struct ts_crypto_hash_setup_out);
+
+    resp_msg.op_handle = op_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: hash_update */
+static rpc_status_t deserialize_hash_update_req(const struct call_param_buf *req_buf,
+                                    uint32_t *op_handle,
+                                    const uint8_t **data, size_t *data_len)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_hash_update_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_hash_update_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        struct tlv_const_iterator req_iter;
+        struct tlv_record decoded_record;
+
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+
+        *op_handle = recv_msg.op_handle;
+
+        tlv_const_iterator_begin(&req_iter,
+            (uint8_t*)req_buf->data + expected_fixed_len,
+            req_buf->data_len - expected_fixed_len);
+
+        if (tlv_find_decode(&req_iter, TS_CRYPTO_HASH_UPDATE_IN_TAG_DATA, &decoded_record)) {
+
+            *data = decoded_record.value;
+            *data_len = decoded_record.length;
+        }
+        else {
+            /* Default to a zero length data */
+            *data_len = 0;
+        }
+    }
+
+    return rpc_status;
+}
+
+/* Operation: hash_finish */
+static rpc_status_t deserialize_hash_finish_req(const struct call_param_buf *req_buf,
+                                    uint32_t *op_handle)
+{
+    rpc_status_t rpc_status = TS_RPC_ERROR_INVALID_REQ_BODY;
+    struct ts_crypto_hash_finish_in recv_msg;
+    size_t expected_fixed_len = sizeof(struct ts_crypto_hash_finish_in);
+
+    if (expected_fixed_len <= req_buf->data_len) {
+
+        memcpy(&recv_msg, req_buf->data, expected_fixed_len);
+        *op_handle = recv_msg.op_handle;
+        rpc_status = TS_RPC_CALL_ACCEPTED;
+    }
+
+    return rpc_status;
+}
+
+static rpc_status_t serialize_hash_finish_resp(struct call_param_buf *resp_buf,
+                                    const uint8_t *hash, size_t hash_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_HASH_FINISH_OUT_TAG_HASH;
+    out_record.length = hash_len;
+    out_record.value = hash;
+
+    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(hash_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)
 {
@@ -595,7 +712,12 @@
         deserialize_asymmetric_encrypt_req,
         serialize_asymmetric_encrypt_resp,
         deserialize_generate_random_req,
-        serialize_generate_random_resp
+        serialize_generate_random_resp,
+        deserialize_hash_setup_req,
+        serialize_hash_setup_resp,
+        deserialize_hash_update_req,
+        deserialize_hash_finish_req,
+        serialize_hash_finish_resp
     };
 
     return &instance;
diff --git a/components/service/crypto/test/service/component.cmake b/components/service/crypto/test/service/component.cmake
index 8aad320..be08793 100644
--- a/components/service/crypto/test/service/component.cmake
+++ b/components/service/crypto/test/service/component.cmake
@@ -11,5 +11,5 @@
 target_sources(${TGT} PRIVATE
 	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_scenarios.cpp"
 	"${CMAKE_CURRENT_LIST_DIR}/crypto_service_limit_tests.cpp"
+	"${CMAKE_CURRENT_LIST_DIR}/crypto_test_vectors.cpp"
 	)
-
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.cpp b/components/service/crypto/test/service/crypto_service_scenarios.cpp
index 7056b4a..276a860 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.cpp
+++ b/components/service/crypto/test/service/crypto_service_scenarios.cpp
@@ -7,422 +7,449 @@
 #include <string>
 #include <cstring>
 #include <cstdint>
+#include <vector>
 #include <CppUTest/TestHarness.h>
 #include "crypto_service_scenarios.h"
-
+#include "crypto_test_vectors.h"
 
 crypto_service_scenarios::crypto_service_scenarios(crypto_client *crypto_client) :
-    m_crypto_client(crypto_client)
+	m_crypto_client(crypto_client)
 {
 
 }
 
 crypto_service_scenarios::~crypto_service_scenarios()
 {
-    delete m_crypto_client;
-    m_crypto_client = NULL;
+	delete m_crypto_client;
+	m_crypto_client = NULL;
 }
 
 void crypto_service_scenarios::generateVolatileKeys()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
-    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+	psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate first key */
-     psa_key_id_t key_id_1;
-    status = m_crypto_client->generate_key(&attributes, &key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate first key */
+	 psa_key_id_t key_id_1;
+	status = m_crypto_client->generate_key(&attributes, &key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* And another */
-     psa_key_id_t key_id_2;
-    status = m_crypto_client->generate_key(&attributes, &key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* And another */
+	 psa_key_id_t key_id_2;
+	status = m_crypto_client->generate_key(&attributes, &key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Expect the key IDs to be different */
-    CHECK(key_id_1 != key_id_2);
+	/* Expect the key IDs to be different */
+	CHECK(key_id_1 != key_id_2);
 
-    /* Remove the keys */
-    status = m_crypto_client->destroy_key(key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->destroy_key(key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the keys */
+	status = m_crypto_client->destroy_key(key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->destroy_key(key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 }
 
 void crypto_service_scenarios::generatePersistentKeys()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
 
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
-    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+	psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* First try and generate a key with an invalid key id */
-    psa_key_id_t key_id;
-    psa_set_key_id(&attributes, 0);
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_ERROR_INVALID_HANDLE, status);
+	/* First try and generate a key with an invalid key id */
+	psa_key_id_t key_id;
+	psa_set_key_id(&attributes, 0);
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_ERROR_INVALID_HANDLE, status);
 
-    /* Generate first key */
-    psa_key_id_t key_id_1;
-    psa_set_key_id(&attributes, 100000);
-    status = m_crypto_client->generate_key(&attributes, &key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK_EQUAL(100000, key_id_1);
+	/* Generate first key */
+	psa_key_id_t key_id_1;
+	psa_set_key_id(&attributes, 100000);
+	status = m_crypto_client->generate_key(&attributes, &key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK_EQUAL(100000, key_id_1);
 
-    /* And another */
-    psa_key_id_t key_id_2;
-    psa_set_key_id(&attributes, 2);
-    status = m_crypto_client->generate_key(&attributes, &key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK_EQUAL(2, key_id_2);
+	/* And another */
+	psa_key_id_t key_id_2;
+	psa_set_key_id(&attributes, 2);
+	status = m_crypto_client->generate_key(&attributes, &key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK_EQUAL(2, key_id_2);
 
-    /* Remove the keys */
-    status = m_crypto_client->destroy_key(key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->destroy_key(key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the keys */
+	status = m_crypto_client->destroy_key(key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->destroy_key(key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 }
 
 void crypto_service_scenarios::exportPublicKey()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id;
 
-    psa_set_key_id(&attributes, 10);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
-    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_id(&attributes, 10);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH);
+	psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Export the public key */
-    uint8_t key_buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
-    size_t key_len = 0;
+	/* Export the public key */
+	uint8_t key_buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+	size_t key_len = 0;
 
-    status = m_crypto_client->export_public_key(key_id, key_buf, sizeof(key_buf), &key_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK_TRUE(key_len > 0);
+	status = m_crypto_client->export_public_key(key_id, key_buf, sizeof(key_buf), &key_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK_TRUE(key_len > 0);
 
-    /* Remove the key */
-    status = m_crypto_client->destroy_key(key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the key */
+	status = m_crypto_client->destroy_key(key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
 void crypto_service_scenarios::exportAndImportKeyPair()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id_1;
-    psa_key_id_t key_id_2;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id_1;
+	psa_key_id_t key_id_2;
 
-    psa_set_key_id(&attributes, 11);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT);
-    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_id(&attributes, 11);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_EXPORT);
+	psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Export the key pair */
-    uint8_t key_buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
-    size_t key_len = 0;
+	/* Export the key pair */
+	uint8_t key_buf[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
+	size_t key_len = 0;
 
-    status = m_crypto_client->export_key(key_id_1, key_buf, sizeof(key_buf), &key_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK(key_len > 0);
+	status = m_crypto_client->export_key(key_id_1, key_buf, sizeof(key_buf), &key_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK(key_len > 0);
 
-    /* Import the key pair value with a different key id */
-    psa_set_key_id(&attributes, 12);
-    status = m_crypto_client->import_key(&attributes, key_buf, key_len, &key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Import the key pair value with a different key id */
+	psa_set_key_id(&attributes, 12);
+	status = m_crypto_client->import_key(&attributes, key_buf, key_len, &key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Remove the keys */
-    status = m_crypto_client->destroy_key(key_id_1);
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->destroy_key(key_id_2);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the keys */
+	status = m_crypto_client->destroy_key(key_id_1);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->destroy_key(key_id_2);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
 void crypto_service_scenarios::signAndVerifyHash()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id;
 
-    psa_set_key_id(&attributes, 13);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
-    psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_id(&attributes, 13);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+	psa_set_key_algorithm(&attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Sign a hash */
-    uint8_t hash[20];
-    uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
-    size_t signature_length;
+	/* Sign a hash */
+	uint8_t hash[20];
+	uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
+	size_t signature_length;
 
-    memset(hash, 0x71, sizeof(hash));
+	memset(hash, 0x71, sizeof(hash));
 
-    status = m_crypto_client->sign_hash(key_id,
-        PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, sizeof(signature), &signature_length);
+	status = m_crypto_client->sign_hash(key_id,
+		PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, sizeof(signature), &signature_length);
 
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK(signature_length > 0);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK(signature_length > 0);
 
-    /* Verify the signature */
-    status = m_crypto_client->verify_hash(key_id,
-        PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, signature_length);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Verify the signature */
+	status = m_crypto_client->verify_hash(key_id,
+		PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, signature_length);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Change the hash and expect verify to fail */
-    hash[0] = 0x72;
-    status = m_crypto_client->verify_hash(key_id,
-        PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, signature_length);
-    CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
+	/* Change the hash and expect verify to fail */
+	hash[0] = 0x72;
+	status = m_crypto_client->verify_hash(key_id,
+		PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, signature_length);
+	CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
 
-    /* Remove the key */
-    status = m_crypto_client->destroy_key(key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the key */
+	status = m_crypto_client->destroy_key(key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
 void crypto_service_scenarios::signAndVerifyEat()
 {
-    /* Sign and verify a hash using EAT key type and algorithm */
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id;
+	/* Sign and verify a hash using EAT key type and algorithm */
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id;
 
-    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
+	psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH);
 
-    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1));
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Sign a hash */
-    uint8_t hash[64];
-    uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
-    size_t signature_length;
+	/* Sign a hash */
+	uint8_t hash[64];
+	uint8_t signature[PSA_SIGNATURE_MAX_SIZE];
+	size_t signature_length;
 
-    memset(hash, 0x71, sizeof(hash));
+	memset(hash, 0x71, sizeof(hash));
 
-    status = m_crypto_client->sign_hash(key_id,
-        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, sizeof(signature), &signature_length);
+	status = m_crypto_client->sign_hash(key_id,
+		PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, sizeof(signature), &signature_length);
 
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    CHECK(signature_length > 0);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	CHECK(signature_length > 0);
 
-    /* Verify the signature */
-    status = m_crypto_client->verify_hash(key_id,
-        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, signature_length);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Verify the signature */
+	status = m_crypto_client->verify_hash(key_id,
+		PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, signature_length);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Change the hash and expect verify to fail */
-    hash[0] = 0x72;
-    status = m_crypto_client->verify_hash(key_id,
-        PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
-        signature, signature_length);
-    CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
+	/* Change the hash and expect verify to fail */
+	hash[0] = 0x72;
+	status = m_crypto_client->verify_hash(key_id,
+		PSA_ALG_ECDSA(PSA_ALG_SHA_256), hash, sizeof(hash),
+		signature, signature_length);
+	CHECK_EQUAL(PSA_ERROR_INVALID_SIGNATURE, status);
 
-    /* Remove the key */
-    status = m_crypto_client->destroy_key(key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the key */
+	status = m_crypto_client->destroy_key(key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
 void crypto_service_scenarios::asymEncryptDecrypt()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id;
 
-    psa_set_key_id(&attributes, 14);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
-    psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
-    psa_set_key_bits(&attributes, 256);
+	psa_set_key_id(&attributes, 14);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
+	psa_set_key_algorithm(&attributes, PSA_ALG_RSA_PKCS1V15_CRYPT);
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
+	psa_set_key_bits(&attributes, 256);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Encrypt a message */
-    uint8_t message[] = {'q','u','i','c','k','b','r','o','w','n','f','o','x'};
-    uint8_t ciphertext[256];
-    size_t ciphertext_len = 0;
+	/* Encrypt a message */
+	uint8_t message[] = {'q','u','i','c','k','b','r','o','w','n','f','o','x'};
+	uint8_t ciphertext[256];
+	size_t ciphertext_len = 0;
 
-    status = m_crypto_client->asymmetric_encrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
-                            message, sizeof(message), NULL, 0,
-                            ciphertext, sizeof(ciphertext), &ciphertext_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->asymmetric_encrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
+							message, sizeof(message), NULL, 0,
+							ciphertext, sizeof(ciphertext), &ciphertext_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Decrypt it */
-    uint8_t plaintext[256];
-    size_t plaintext_len = 0;
+	/* Decrypt it */
+	uint8_t plaintext[256];
+	size_t plaintext_len = 0;
 
-    status = m_crypto_client->asymmetric_decrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
-                            ciphertext, ciphertext_len, NULL, 0,
-                            plaintext, sizeof(plaintext), &plaintext_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->asymmetric_decrypt(key_id, PSA_ALG_RSA_PKCS1V15_CRYPT,
+							ciphertext, ciphertext_len, NULL, 0,
+							plaintext, sizeof(plaintext), &plaintext_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Expect the encrypted/decrypted message to match theh original */
-    CHECK_EQUAL(sizeof(message), plaintext_len);
-    MEMCMP_EQUAL(message, plaintext, plaintext_len);
+	/* Expect the encrypted/decrypted message to match theh original */
+	CHECK_EQUAL(sizeof(message), plaintext_len);
+	MEMCMP_EQUAL(message, plaintext, plaintext_len);
 
-    /* Remove the key */
-    status = m_crypto_client->destroy_key(key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the key */
+	status = m_crypto_client->destroy_key(key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 }
 
 void crypto_service_scenarios::asymEncryptDecryptWithSalt()
 {
-    psa_status_t status;
-    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    psa_key_id_t key_id;
+	psa_status_t status;
+	psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+	psa_key_id_t key_id;
 
-    psa_set_key_id(&attributes, 15);
-    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
-    psa_set_key_algorithm(&attributes,  PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
-    psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
-    psa_set_key_bits(&attributes, 1024);
+	psa_set_key_id(&attributes, 15);
+	psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
+	psa_set_key_algorithm(&attributes,  PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
+	psa_set_key_type(&attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
+	psa_set_key_bits(&attributes, 1024);
 
-    /* Generate a key */
-    status = m_crypto_client->generate_key(&attributes, &key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate a key */
+	status = m_crypto_client->generate_key(&attributes, &key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    psa_reset_key_attributes(&attributes);
+	psa_reset_key_attributes(&attributes);
 
-    /* Encrypt a message */
-    uint8_t message[] = {'q','u','i','c','k','b','r','o','w','n','f','o','x'};
-    uint8_t ciphertext[128];
-    size_t ciphertext_len = 0;
+	/* Encrypt a message */
+	uint8_t message[] = {'q','u','i','c','k','b','r','o','w','n','f','o','x'};
+	uint8_t ciphertext[128];
+	size_t ciphertext_len = 0;
 
-    /* With salt */
-    uint8_t salt[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
+	/* With salt */
+	uint8_t salt[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
 
-    status = m_crypto_client->asymmetric_encrypt(key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
-                            message, sizeof(message),
-                            salt, sizeof(salt),
-                            ciphertext, sizeof(ciphertext), &ciphertext_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->asymmetric_encrypt(key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
+							message, sizeof(message),
+							salt, sizeof(salt),
+							ciphertext, sizeof(ciphertext), &ciphertext_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Decrypt it */
-    uint8_t plaintext[256];
-    size_t plaintext_len = 0;
+	/* Decrypt it */
+	uint8_t plaintext[256];
+	size_t plaintext_len = 0;
 
-    status = m_crypto_client->asymmetric_decrypt(key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
-                            ciphertext, ciphertext_len,
-                            salt, sizeof(salt),
-                            plaintext, sizeof(plaintext), &plaintext_len);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->asymmetric_decrypt(key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
+							ciphertext, ciphertext_len,
+							salt, sizeof(salt),
+							plaintext, sizeof(plaintext), &plaintext_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* Expect the encrypted/decrypted message to match theh original */
-    CHECK_EQUAL(sizeof(message), plaintext_len);
-    MEMCMP_EQUAL(message, plaintext, plaintext_len);
+	/* Expect the encrypted/decrypted message to match theh original */
+	CHECK_EQUAL(sizeof(message), plaintext_len);
+	MEMCMP_EQUAL(message, plaintext, plaintext_len);
 
-    /* Remove the key */
-    status = m_crypto_client->destroy_key(key_id);
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Remove the key */
+	status = m_crypto_client->destroy_key(key_id);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+}
+
+void crypto_service_scenarios::calculateHash()
+{
+	psa_status_t status;
+	std::vector<uint8_t> input;
+	std::vector<uint8_t> expected_output;
+	uint8_t output[PSA_HASH_MAX_SIZE];
+	size_t output_len;
+
+	crypto_test_vectors::plaintext_1_len_610(input);
+	crypto_test_vectors::sha256_1(expected_output);
+
+	uint32_t op_handle = 0;
+
+	status = m_crypto_client->hash_setup(&op_handle, PSA_ALG_SHA_256);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	status = m_crypto_client->hash_update(op_handle, &input[0], input.size());
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	status = m_crypto_client->hash_finish(op_handle, output, sizeof(output), &output_len);
+	CHECK_EQUAL(PSA_SUCCESS, status);
+
+	UNSIGNED_LONGS_EQUAL(expected_output.size(), output_len);
+	MEMCMP_EQUAL(&expected_output[0], &output[0], output_len);
 }
 
 void crypto_service_scenarios::generateRandomNumbers()
 {
-    psa_status_t status;
-    uint8_t num1_8bit[1];
-    uint8_t num2_8bit[1];
-    uint8_t num3_16bit[2];
-    uint8_t num4_16bit[2];
-    uint8_t num5_24bit[3];
-    uint8_t num6_24bit[3];
-    uint8_t num7_32bit[4];
-    uint8_t num8_32bit[4];
-    uint8_t num9_64bit[8];
-    uint8_t num10_64bit[8];
-    uint8_t num11_128bit[16];
-    uint8_t num12_128bit[16];
+	psa_status_t status;
+	uint8_t num1_8bit[1];
+	uint8_t num2_8bit[1];
+	uint8_t num3_16bit[2];
+	uint8_t num4_16bit[2];
+	uint8_t num5_24bit[3];
+	uint8_t num6_24bit[3];
+	uint8_t num7_32bit[4];
+	uint8_t num8_32bit[4];
+	uint8_t num9_64bit[8];
+	uint8_t num10_64bit[8];
+	uint8_t num11_128bit[16];
+	uint8_t num12_128bit[16];
 
-    /* Clear all buffers */
-    memset(num1_8bit, 0, sizeof(num1_8bit));
-    memset(num2_8bit, 0, sizeof(num2_8bit));
-    memset(num3_16bit, 0, sizeof(num3_16bit));
-    memset(num4_16bit, 0, sizeof(num4_16bit));
-    memset(num5_24bit, 0, sizeof(num5_24bit));
-    memset(num6_24bit, 0, sizeof(num6_24bit));
-    memset(num7_32bit, 0, sizeof(num7_32bit));
-    memset(num8_32bit, 0, sizeof(num8_32bit));
-    memset(num9_64bit, 0, sizeof(num9_64bit));
-    memset(num10_64bit, 0, sizeof(num10_64bit));
-    memset(num11_128bit, 0, sizeof(num11_128bit));
-    memset(num12_128bit, 0, sizeof(num12_128bit));
+	/* Clear all buffers */
+	memset(num1_8bit, 0, sizeof(num1_8bit));
+	memset(num2_8bit, 0, sizeof(num2_8bit));
+	memset(num3_16bit, 0, sizeof(num3_16bit));
+	memset(num4_16bit, 0, sizeof(num4_16bit));
+	memset(num5_24bit, 0, sizeof(num5_24bit));
+	memset(num6_24bit, 0, sizeof(num6_24bit));
+	memset(num7_32bit, 0, sizeof(num7_32bit));
+	memset(num8_32bit, 0, sizeof(num8_32bit));
+	memset(num9_64bit, 0, sizeof(num9_64bit));
+	memset(num10_64bit, 0, sizeof(num10_64bit));
+	memset(num11_128bit, 0, sizeof(num11_128bit));
+	memset(num12_128bit, 0, sizeof(num12_128bit));
 
-    /* Generate some different size random numbers */
-    status = m_crypto_client->generate_random(num1_8bit, sizeof(num1_8bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num2_8bit, sizeof(num2_8bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num3_16bit, sizeof(num3_16bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num4_16bit, sizeof(num4_16bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num5_24bit, sizeof(num5_24bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num6_24bit, sizeof(num6_24bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num7_32bit, sizeof(num7_32bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num8_32bit, sizeof(num8_32bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num9_64bit, sizeof(num9_64bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num10_64bit, sizeof(num10_64bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num11_128bit, sizeof(num11_128bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
-    status = m_crypto_client->generate_random(num12_128bit, sizeof(num12_128bit));
-    CHECK_EQUAL(PSA_SUCCESS, status);
+	/* Generate some different size random numbers */
+	status = m_crypto_client->generate_random(num1_8bit, sizeof(num1_8bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num2_8bit, sizeof(num2_8bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num3_16bit, sizeof(num3_16bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num4_16bit, sizeof(num4_16bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num5_24bit, sizeof(num5_24bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num6_24bit, sizeof(num6_24bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num7_32bit, sizeof(num7_32bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num8_32bit, sizeof(num8_32bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num9_64bit, sizeof(num9_64bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num10_64bit, sizeof(num10_64bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num11_128bit, sizeof(num11_128bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
+	status = m_crypto_client->generate_random(num12_128bit, sizeof(num12_128bit));
+	CHECK_EQUAL(PSA_SUCCESS, status);
 
-    /* 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);
-    CHECK(memcmp(num11_128bit, num12_128bit, sizeof(num11_128bit)) != 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);
+	CHECK(memcmp(num11_128bit, num12_128bit, sizeof(num11_128bit)) != 0);
 }
diff --git a/components/service/crypto/test/service/crypto_service_scenarios.h b/components/service/crypto/test/service/crypto_service_scenarios.h
index 648baae..ddfaa62 100644
--- a/components/service/crypto/test/service/crypto_service_scenarios.h
+++ b/components/service/crypto/test/service/crypto_service_scenarios.h
@@ -26,6 +26,7 @@
     void exportPublicKey();
     void generatePersistentKeys();
     void generateVolatileKeys();
+    void calculateHash();
 
 private:
     crypto_client *m_crypto_client;
diff --git a/components/service/crypto/test/service/crypto_test_vectors.cpp b/components/service/crypto/test/service/crypto_test_vectors.cpp
new file mode 100644
index 0000000..7f781b4
--- /dev/null
+++ b/components/service/crypto/test/service/crypto_test_vectors.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstring>
+#include "crypto_test_vectors.h"
+
+void crypto_test_vectors::plaintext_1_len_610(std::vector<uint8_t> &plaintext)
+{
+	/* Plaintext 1 - data length 610 bytes */
+	const uint8_t data[] =
+	{
+		0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x00,
+		0x53,0x70,0x65,0x63,0x20,0x49,0x44,0x20,0x45,0x76,0x65,0x6e,0x74,0x30,0x33,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01,0x01,0x00,0x00,0x00,0x0b,0x00,0x20,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,
+		0x00,0x00,0x00,0x53,0x74,0x61,0x72,0x74,0x75,0x70,0x4c,0x6f,0x63,0x61,0x6c,0x69,
+		0x74,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
+		0x0b,0x00,0xa8,0x4f,0xb4,0x7b,0x54,0xd9,0x4b,0xab,0x49,0x73,0x63,0xf7,0x9b,0xfc,
+		0x66,0xcb,0x85,0x12,0xab,0x18,0x6f,0x24,0x74,0x01,0x5d,0xcf,0x33,0xf3,0x80,0x9e,
+		0x9b,0x20,0x05,0x00,0x00,0x00,0x42,0x4c,0x5f,0x32,0x00,0x00,0x00,0x00,0x00,0x01,
+		0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x2f,0xd3,0x43,0x6c,0x6f,0xef,0x9b,
+		0x11,0xc2,0x16,0xdd,0x1f,0x8b,0xdf,0x9b,0xa5,0x24,0x14,0xa5,0xc1,0x97,0x0c,0x3a,
+		0x6c,0x78,0xbf,0xef,0x64,0x0f,0xc1,0x23,0xe1,0x06,0x00,0x00,0x00,0x42,0x4c,0x5f,
+		0x33,0x31,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,
+		0x00,0xf3,0xde,0x4e,0x17,0xa1,0xa5,0xa7,0xfe,0xd9,0xd9,0xf4,0x16,0x3c,0x49,0x36,
+		0x7e,0xae,0xf7,0x2f,0x2a,0xa8,0x87,0xe6,0xb6,0x22,0x89,0xcd,0x27,0xdc,0x1c,0x80,
+		0x25,0x0a,0x00,0x00,0x00,0x48,0x57,0x5f,0x43,0x4f,0x4e,0x46,0x49,0x47,0x00,0x00,
+		0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x4e,0xe4,0x8e,
+		0x5a,0xe6,0x50,0xed,0xe0,0xb5,0xa3,0x54,0x8a,0x1f,0xd6,0x0e,0x8a,0xea,0x0e,0x71,
+		0x75,0x0e,0xa4,0x3f,0x82,0x76,0xce,0xaf,0xcd,0x7c,0xb0,0x91,0xe0,0x0e,0x00,0x00,
+		0x00,0x53,0x4f,0x43,0x5f,0x46,0x57,0x5f,0x43,0x4f,0x4e,0x46,0x49,0x47,0x00,0x00,
+		0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x62,0x22,0x4f,
+		0x0f,0xb0,0x5d,0xb4,0x77,0x1b,0x3f,0xa5,0x2e,0xab,0x76,0x1e,0x61,0x17,0xb8,0xc6,
+		0x6e,0xac,0x8c,0xc8,0x4d,0x2e,0xb0,0x7d,0x70,0x08,0x60,0x4b,0x41,0x06,0x00,0x00,
+		0x00,0x42,0x4c,0x5f,0x33,0x32,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,
+		0x00,0x00,0x00,0x0b,0x00,0x39,0xd2,0xb8,0x5d,0x93,0x5d,0xf6,0xd8,0xf8,0xed,0x0c,
+		0x1a,0x3a,0xe3,0xc8,0x90,0x72,0x19,0xf4,0x88,0x5c,0x79,0x15,0x05,0x7b,0xf0,0x76,
+		0xdb,0xc1,0x4c,0x5d,0x77,0x12,0x00,0x00,0x00,0x42,0x4c,0x33,0x32,0x5f,0x45,0x58,
+		0x54,0x52,0x41,0x31,0x5f,0x49,0x4d,0x41,0x47,0x45,0x00,0x00,0x00,0x00,0x00,0x01,
+		0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0xb5,0xd6,0x08,0x61,0xdd,0xfa,0x6d,
+		0xda,0xa3,0xf7,0xa5,0xde,0xd6,0x8f,0x6f,0x39,0x25,0xb1,0x57,0xfa,0x3e,0xdb,0x46,
+		0x42,0x58,0x24,0x8e,0x81,0x1c,0x45,0x5d,0x38,0x06,0x00,0x00,0x00,0x42,0x4c,0x5f,
+		0x33,0x33,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,
+		0x00,0x25,0x10,0x60,0x5d,0xd4,0xbc,0x9d,0x82,0x7a,0x16,0x9f,0x8a,0xcc,0x47,0x95,
+		0xa6,0xfd,0xca,0xa0,0xc1,0x2b,0xc9,0x99,0x8f,0x51,0x20,0xff,0xc6,0xed,0x74,0x68,
+		0x5a,0x0d,0x00,0x00,0x00,0x4e,0x54,0x5f,0x46,0x57,0x5f,0x43,0x4f,0x4e,0x46,0x49,
+		0x47,0x00
+	};
+
+	plaintext.resize(sizeof(data));
+	memcpy(&plaintext[0], data, sizeof(data));
+}
+
+void crypto_test_vectors::sha256_1(std::vector<uint8_t> &hash)
+{
+	/* SHA256 for plaintext_1 */
+	const uint8_t data[] =
+	{
+		0x47, 0x25, 0x0e, 0xe2, 0x39, 0xe2, 0x87, 0xfc,
+		0x07, 0x0d, 0xce, 0x67, 0xe8, 0x96, 0x6f, 0xc8,
+		0x42, 0xae, 0xe7, 0xaa, 0x7f, 0xa3, 0xbc, 0x3c,
+		0xc9, 0x8e, 0x7e, 0x7a, 0xca, 0x24, 0x2c, 0xfc
+	};
+
+	hash.resize(sizeof(data));
+	memcpy(&hash[0], data, sizeof(data));
+}
diff --git a/components/service/crypto/test/service/crypto_test_vectors.h b/components/service/crypto/test/service/crypto_test_vectors.h
new file mode 100644
index 0000000..828fafb
--- /dev/null
+++ b/components/service/crypto/test/service/crypto_test_vectors.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cstdint>
+#include <vector>
+
+/*
+ * A selection of test vectors in the form of blocks of plaintext,
+ * ciphertext, expected hashes etc.
+ */
+class crypto_test_vectors
+{
+public:
+
+	static void plaintext_1_len_610(std::vector<uint8_t> &plaintext);
+	static void sha256_1(std::vector<uint8_t> &hash);
+
+};
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
index 9ceb0d5..094969c 100644
--- 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
@@ -92,6 +92,11 @@
     m_scenarios->asymEncryptDecryptWithSalt();
 }
 
+TEST(CryptoServicePackedcTests, calculateHash)
+{
+    m_scenarios->calculateHash();
+}
+
 TEST(CryptoServicePackedcTests, generateRandomNumbers)
 {
     m_scenarios->generateRandomNumbers();
diff --git a/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.cpp b/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.cpp
index 6bf43fe..0c790c9 100644
--- a/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.cpp
+++ b/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.cpp
@@ -119,3 +119,21 @@
 
     return psa_status;
 }
+
+psa_status_t psa_crypto_api_client::hash_setup(uint32_t *op_handle,
+							psa_algorithm_t alg)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_crypto_api_client::hash_update(uint32_t op_handle,
+							const uint8_t *input, size_t input_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
+
+psa_status_t psa_crypto_api_client::hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length)
+{
+	return PSA_ERROR_NOT_SUPPORTED;
+}
diff --git a/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.h b/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.h
index 66f4431..fe72bf2 100644
--- a/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.h
+++ b/components/service/crypto/test/service/psa_crypto_api/psa_crypto_api_client.h
@@ -15,42 +15,50 @@
 class psa_crypto_api_client : public crypto_client
 {
 public:
-    psa_crypto_api_client();
-     virtual ~psa_crypto_api_client();
+	psa_crypto_api_client();
+	 virtual ~psa_crypto_api_client();
 
-    /* Key lifecycle methods */
-    psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id);
-    psa_status_t destroy_key(psa_key_id_t id);
-    psa_status_t import_key(const psa_key_attributes_t *attributes,
-                            const uint8_t *data, size_t data_length, psa_key_id_t *id);
+	/* Key lifecycle methods */
+	psa_status_t generate_key(const psa_key_attributes_t *attributes, psa_key_id_t *id);
+	psa_status_t destroy_key(psa_key_id_t id);
+	psa_status_t import_key(const psa_key_attributes_t *attributes,
+							const uint8_t *data, size_t data_length, psa_key_id_t *id);
 
-    /* Key export methods */
-    psa_status_t export_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size,
-                            size_t *data_length);
-    psa_status_t export_public_key(psa_key_id_t id,
-                            uint8_t *data, size_t data_size, size_t *data_length);
+	/* Key export methods */
+	psa_status_t export_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size,
+							size_t *data_length);
+	psa_status_t export_public_key(psa_key_id_t id,
+							uint8_t *data, size_t data_size, size_t *data_length);
 
-    /* Sign/verify methods */
-    psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, psa_algorithm_t alg,
-                            const uint8_t *hash, size_t hash_length,
-                            const uint8_t *signature, size_t signature_length);
+	/* Sign/verify methods */
+	psa_status_t sign_hash(psa_key_id_t id, 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_id_t id, 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_id_t id, 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_id_t id, 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);
+	/* Asymmetric encrypt/decrypt */
+	psa_status_t asymmetric_encrypt(psa_key_id_t id, 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_id_t id, 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);
+	/* Random number generation */
+	psa_status_t generate_random(uint8_t *output, size_t output_size);
+
+	/* Hash methods */
+	psa_status_t hash_setup(uint32_t *op_handle,
+							psa_algorithm_t alg);
+	psa_status_t hash_update(uint32_t op_handle,
+							const uint8_t *input, size_t input_length);
+	psa_status_t hash_finish(uint32_t op_handle,
+							uint8_t *hash, size_t hash_size, size_t *hash_length);
 };
 
 #endif /* PSA_CRYPTO_API_CLIENT_H */