Factor hash operations to sub-provider

To allow for per-deployment configuration of supported crypto
operations, hash operations have been factored to a separate
sub-provider.  This approach allows extended operations to
be supported without bloating the base crypto provider.

Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: I7a785762e8958c916a2668dba96efb533908bc8a
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
index a049c43..b5a7ca0 100644
--- a/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.cpp
@@ -5,16 +5,13 @@
  */
 
 #include "standalone_crypto_client.h"
-#include <protocols/rpc/common/packed-c/status.h>
-#include <protocols/service/psa/packed-c/status.h>
-#include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
-#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
 #include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
 #include <service/secure_storage/backend/secure_flash_store/secure_flash_store.h>
 
 standalone_crypto_client::standalone_crypto_client() :
     test_crypto_client(),
-    m_crypto_provider(),
+    m_crypto_provider(NULL),
     m_storage_provider(),
     m_storage_client(),
     m_crypto_caller(),
@@ -56,22 +53,17 @@
                         TS_RPC_CALL_ACCEPTED, PSA_ERROR_STORAGE_FAILURE);
         }
 
-        struct rpc_interface *crypto_ep = NULL;
+        struct rpc_interface *crypto_iface = NULL;
         struct storage_backend *client_storage_backend =
             secure_storage_client_init(&m_storage_client, storage_caller);
 
         if (mbedcrypto_backend_init(client_storage_backend, 0) == PSA_SUCCESS) {
 
-            crypto_ep = crypto_provider_init(&m_crypto_provider);
-
-            crypto_provider_register_serializer(&m_crypto_provider,
-                    TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
-
-            crypto_provider_register_serializer(&m_crypto_provider,
-                    TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+            m_crypto_provider = crypto_provider_factory_create();
+            crypto_iface = service_provider_get_rpc_interface(&m_crypto_provider->base_provider);
         }
 
-        struct rpc_caller *crypto_caller = direct_caller_init_default(&m_crypto_caller, crypto_ep);
+        struct rpc_caller *crypto_caller = direct_caller_init_default(&m_crypto_caller, crypto_iface);
         rpc_caller_set_encoding_scheme(crypto_caller, TS_RPC_ENCODING_PROTOBUF);
 
         crypto_client::set_caller(crypto_caller);
@@ -86,7 +78,7 @@
 
     if (should_do) {
 
-        crypto_provider_deinit(&m_crypto_provider);
+        crypto_provider_factory_destroy(m_crypto_provider);
         secure_storage_provider_deinit(&m_storage_provider);
         secure_storage_client_deinit(&m_storage_client);
 
diff --git a/components/service/crypto/client/test/standalone/standalone_crypto_client.h b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
index 0b68101..8df0861 100644
--- a/components/service/crypto/client/test/standalone/standalone_crypto_client.h
+++ b/components/service/crypto/client/test/standalone/standalone_crypto_client.h
@@ -43,7 +43,7 @@
 private:
     bool is_fault_supported(enum fault_code code) const;
 
-    struct crypto_provider m_crypto_provider;
+    struct crypto_provider *m_crypto_provider;
     struct secure_storage_provider m_storage_provider;
     struct secure_storage_client m_storage_client;
     struct direct_caller m_crypto_caller;
diff --git a/components/service/crypto/factory/crypto_provider_factory.h b/components/service/crypto/factory/crypto_provider_factory.h
new file mode 100644
index 0000000..f4b1491
--- /dev/null
+++ b/components/service/crypto/factory/crypto_provider_factory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef CRYPTO_PROVIDER_FACTORY_H
+#define CRYPTO_PROVIDER_FACTORY_H
+
+#include <service/crypto/provider/crypto_provider.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Defines a common interface for creating crypto providers.
+ * A concrete factory will construct base crypto providers,
+ * extended with any extra capabilities needed for a
+ * deployment.
+ */
+
+/**
+ * \brief Factory method to create an initialised crypto provider.
+ *
+ * \return A pointer to the initialised crypto provider or NULL on failure
+ */
+struct crypto_provider *crypto_provider_factory_create(void);
+
+/**
+ * \brief Destroys a created crypto provider
+ *
+ * \param[in] provider    The crypto provider to destroy
+  */
+void crypto_provider_factory_destroy(struct crypto_provider *provider);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CRYPTO_PROVIDER_FACTORY_H */
diff --git a/components/service/crypto/factory/full/component.cmake b/components/service/crypto/factory/full/component.cmake
new file mode 100644
index 0000000..0fecfbf
--- /dev/null
+++ b/components/service/crypto/factory/full/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_provider_factory.c"
+	)
diff --git a/components/service/crypto/factory/full/crypto_provider_factory.c b/components/service/crypto/factory/full/crypto_provider_factory.c
new file mode 100644
index 0000000..482c0be
--- /dev/null
+++ b/components/service/crypto/factory/full/crypto_provider_factory.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <service/crypto/factory/crypto_provider_factory.h>
+#include <service/crypto/provider/crypto_provider.h>
+#include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
+#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
+#include <service/crypto/provider/extension/hash/hash_provider.h>
+#include <service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.h>
+
+/**
+ * A crypto provider factory that constucts a full-featured
+ * crypto provider that is extended to support the full set of crypto
+ * operations.  This factory is only capable of constructing
+ * a single service provider instance.
+ */
+
+static struct default_crypto_provider
+{
+	struct crypto_provider crypto_provider;
+	struct hash_provider hash_provider;
+
+} instance;
+
+struct crypto_provider *crypto_provider_factory_create(void)
+{
+	/* Initialize the base crypto provider */
+	crypto_provider_init(&instance.crypto_provider);
+
+	crypto_provider_register_serializer(&instance.crypto_provider,
+		TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
+
+	crypto_provider_register_serializer(&instance.crypto_provider,
+		TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+
+	/* Extend with hash operations */
+	hash_provider_init(&instance.hash_provider);
+
+	hash_provider_register_serializer(&instance.hash_provider,
+		TS_RPC_ENCODING_PACKED_C, packedc_hash_provider_serializer_instance());
+
+	crypto_provider_extend(&instance.crypto_provider, &instance.hash_provider.base_provider);
+
+	return &instance.crypto_provider;
+}
+
+/**
+ * \brief Destroys a created crypto provider
+ *
+ * \param[in] provider    The crypto provider to destroy
+  */
+void crypto_provider_factory_destroy(struct crypto_provider *provider)
+{
+	(void)provider;
+	crypto_provider_deinit(&instance.crypto_provider);
+	hash_provider_deinit(&instance.hash_provider);
+}
diff --git a/components/service/crypto/provider/crypto_provider.c b/components/service/crypto/provider/crypto_provider.c
index 6777fd2..394f493 100644
--- a/components/service/crypto/provider/crypto_provider.c
+++ b/components/service/crypto/provider/crypto_provider.c
@@ -22,9 +22,6 @@
 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);
 static rpc_status_t copy_key_handler(void *context, struct call_req* req);
 static rpc_status_t purge_key_handler(void *context, struct call_req* req);
 static rpc_status_t get_key_attributes_handler(void *context, struct call_req* req);
@@ -42,9 +39,6 @@
 	{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},
 	{TS_CRYPTO_OPCODE_COPY_KEY,          	copy_key_handler},
 	{TS_CRYPTO_OPCODE_PURGE_KEY,          	purge_key_handler},
 	{TS_CRYPTO_OPCODE_GET_KEY_ATTRIBUTES, 	get_key_attributes_handler},
@@ -52,8 +46,6 @@
 
 struct rpc_interface *crypto_provider_init(struct crypto_provider *context)
 {
-	crypto_context_pool_init(&context->context_pool);
-
 	for (size_t encoding = 0; encoding < TS_RPC_ENCODING_LIMIT; ++encoding)
 		context->serializers[encoding] = NULL;
 
@@ -65,7 +57,7 @@
 
 void crypto_provider_deinit(struct crypto_provider *context)
 {
-	crypto_context_pool_deinit(&context->context_pool);
+
 }
 
 void crypto_provider_register_serializer(struct crypto_provider *context,
@@ -661,134 +653,3 @@
 
 	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 crypto_provider *this_instance = (struct 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 crypto_provider *this_instance = (struct 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 crypto_provider *this_instance = (struct 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/crypto_provider.h b/components/service/crypto/provider/crypto_provider.h
index 7cd91a9..788e501 100644
--- a/components/service/crypto/provider/crypto_provider.h
+++ b/components/service/crypto/provider/crypto_provider.h
@@ -11,7 +11,6 @@
 #include <service/common/provider/service_provider.h>
 #include <service/crypto/provider/serializer/crypto_provider_serializer.h>
 #include <protocols/rpc/common/packed-c/encoding.h>
-#include "crypto_context_pool.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -20,7 +19,6 @@
 struct 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/extension/hash/component.cmake b/components/service/crypto/provider/extension/hash/component.cmake
new file mode 100644
index 0000000..66784e1
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/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}/hash_provider.c"
+	)
diff --git a/components/service/crypto/provider/extension/hash/hash_provider.c b/components/service/crypto/provider/extension/hash/hash_provider.c
new file mode 100644
index 0000000..5a7ae3c
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/hash_provider.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+#include <stdlib.h>
+#include <protocols/service/crypto/packed-c/opcodes.h>
+#include <service/crypto/provider/extension/hash/hash_provider.h>
+#include <protocols/rpc/common/packed-c/status.h>
+#include <psa/crypto.h>
+
+/* Service request handlers */
+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_HASH_SETUP,           hash_setup_handler},
+	{TS_CRYPTO_OPCODE_HASH_UPDATE,          hash_update_handler},
+	{TS_CRYPTO_OPCODE_HASH_FINISH,          hash_finish_handler}
+};
+
+void hash_provider_init(struct hash_provider *context)
+{
+	crypto_context_pool_init(&context->context_pool);
+
+	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));
+}
+
+void hash_provider_deinit(struct hash_provider *context)
+{
+	crypto_context_pool_deinit(&context->context_pool);
+}
+
+void hash_provider_register_serializer(struct hash_provider *context,
+	unsigned int encoding, const struct hash_provider_serializer *serializer)
+{
+	if (encoding < TS_RPC_ENCODING_LIMIT)
+		context->serializers[encoding] = serializer;
+}
+
+static const struct hash_provider_serializer* get_serializer(void *context,
+	const struct call_req *req)
+{
+	struct hash_provider *this_instance = (struct hash_provider*)context;
+	const struct hash_provider_serializer* serializer = NULL;
+	unsigned int encoding = call_req_get_encoding(req);
+
+	if (encoding < TS_RPC_ENCODING_LIMIT) serializer = this_instance->serializers[encoding];
+
+	return serializer;
+}
+
+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 hash_provider_serializer *serializer = get_serializer(context, req);
+	struct hash_provider *this_instance = (struct hash_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 hash_provider_serializer *serializer = get_serializer(context, req);
+	struct hash_provider *this_instance = (struct hash_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 hash_provider_serializer *serializer = get_serializer(context, req);
+	struct hash_provider *this_instance = (struct hash_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/extension/hash/hash_provider.h b/components/service/crypto/provider/extension/hash/hash_provider.h
new file mode 100644
index 0000000..0c8e397
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/hash_provider.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HASH_PROVIDER_H
+#define HASH_PROVIDER_H
+
+#include <rpc/common/endpoint/rpc_interface.h>
+#include <service/common/provider/service_provider.h>
+#include <service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h>
+#include <service/crypto/provider/crypto_context_pool.h>
+#include <protocols/rpc/common/packed-c/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A service provider that can be used to add hash operations to the base
+ * crypto provider.
+ */
+struct hash_provider
+{
+	struct service_provider base_provider;
+	struct crypto_context_pool context_pool;
+	const struct hash_provider_serializer *serializers[TS_RPC_ENCODING_LIMIT];
+};
+
+/*
+ * Initializes an instance of the hash service provider.
+ */
+void hash_provider_init(struct hash_provider *context);
+
+/*
+ * When operation of the provider is no longer required, this function
+ * frees any resource used by the previously initialized provider instance.
+ */
+void hash_provider_deinit(struct hash_provider *context);
+
+/*
+ * Register a serializer for supportng a particular parameter encoding.
+ */
+void hash_provider_register_serializer(struct hash_provider *context,
+	unsigned int encoding, const struct hash_provider_serializer *serializer);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* HASH_PROVIDER_H */
diff --git a/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h b/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h
new file mode 100644
index 0000000..5aa3c95
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HASH_PROVIDER_SERIALIZER_H
+#define HASH_PROVIDER_SERIALIZER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <psa/crypto.h>
+#include <rpc/common/endpoint/rpc_interface.h>
+
+/* Provides a common interface for parameter serialization operations
+ * for the hash service provider.
+ */
+struct hash_provider_serializer {
+
+	/* 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 /* HASH_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/extension/hash/serializer/packed-c/component.cmake b/components/service/crypto/provider/extension/hash/serializer/packed-c/component.cmake
new file mode 100644
index 0000000..dca0cbd
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/serializer/packed-c/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}/packedc_hash_provider_serializer.c"
+	)
diff --git a/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c
new file mode 100644
index 0000000..2006f38
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <common/tlv/tlv.h>
+#include <psa/crypto.h>
+#include <protocols/service/crypto/packed-c/hash.h>
+#include "packedc_hash_provider_serializer.h"
+
+/* 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 hash_provider_serializer *packedc_hash_provider_serializer_instance(void)
+{
+	static const struct hash_provider_serializer instance = {
+		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/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.h b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.h
new file mode 100644
index 0000000..e591b0f
--- /dev/null
+++ b/components/service/crypto/provider/extension/hash/serializer/packed-c/packedc_hash_provider_serializer.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PACKEDC_HASH_PROVIDER_SERIALIZER_H
+#define PACKEDC_HASH_PROVIDER_SERIALIZER_H
+
+#include <service/crypto/provider/extension/hash/serializer/hash_provider_serializer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Singleton method to provide access to the packed-c serializer
+ * for the hash service provider.
+ */
+const struct hash_provider_serializer *packedc_hash_provider_serializer_instance(void);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PACKEDC_HASH_PROVIDER_SERIALIZER_H */
diff --git a/components/service/crypto/provider/serializer/crypto_provider_serializer.h b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
index 3feb50b..68940ca 100644
--- a/components/service/crypto/provider/serializer/crypto_provider_serializer.h
+++ b/components/service/crypto/provider/serializer/crypto_provider_serializer.h
@@ -116,25 +116,6 @@
 
     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 b278e89..c70db86 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
@@ -22,7 +22,6 @@
 #include <protocols/service/crypto/packed-c/get_key_attributes.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"
 
@@ -677,122 +676,6 @@
     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)
 {
@@ -820,12 +703,7 @@
         deserialize_asymmetric_encrypt_req,
         serialize_asymmetric_encrypt_resp,
         deserialize_generate_random_req,
-        serialize_generate_random_resp,
-        deserialize_hash_setup_req,
-        serialize_hash_setup_resp,
-        deserialize_hash_update_req,
-        deserialize_hash_finish_req,
-        serialize_hash_finish_resp
+        serialize_generate_random_resp
     };
 
     return &instance;
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.cpp b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
index f245919..c22bb0b 100644
--- a/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.cpp
@@ -5,13 +5,12 @@
  */
 
 #include "crypto_service_context.h"
-#include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
-#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
 #include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
 
 crypto_service_context::crypto_service_context(const char *sn) :
     standalone_service_context(sn),
-    m_crypto_provider(),
+    m_crypto_provider(NULL),
     m_storage_client(),
     m_null_store(),
     m_storage_service_context(NULL),
@@ -59,20 +58,15 @@
     }
 
     /* Initialise the crypto service provider */
-    struct rpc_interface *crypto_ep = NULL;
+    struct rpc_interface *crypto_iface = NULL;
 
     if (mbedcrypto_backend_init(storage_backend, 0) == PSA_SUCCESS) {
 
-        crypto_ep = crypto_provider_init(&m_crypto_provider);
-
-        crypto_provider_register_serializer(&m_crypto_provider,
-                        TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
-
-        crypto_provider_register_serializer(&m_crypto_provider,
-                        TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+        m_crypto_provider = crypto_provider_factory_create();
+        crypto_iface = service_provider_get_rpc_interface(&m_crypto_provider->base_provider);
     }
 
-    standalone_service_context::set_rpc_interface(crypto_ep);
+    standalone_service_context::set_rpc_interface(crypto_iface);
 }
 
 void crypto_service_context::do_deinit()
@@ -87,7 +81,7 @@
         m_storage_service_context = NULL;
     }
 
-    crypto_provider_deinit(&m_crypto_provider);
+    crypto_provider_factory_destroy(m_crypto_provider);
     secure_storage_client_deinit(&m_storage_client);
     null_store_deinit(&m_null_store);
 }
diff --git a/components/service/locator/standalone/services/crypto/crypto_service_context.h b/components/service/locator/standalone/services/crypto/crypto_service_context.h
index 1b842aa..6010a4e 100644
--- a/components/service/locator/standalone/services/crypto/crypto_service_context.h
+++ b/components/service/locator/standalone/services/crypto/crypto_service_context.h
@@ -24,7 +24,7 @@
     void do_init();
     void do_deinit();
 
-    struct crypto_provider m_crypto_provider;
+    struct crypto_provider *m_crypto_provider;
     struct secure_storage_client m_storage_client;
     struct null_store m_null_store;
     struct service_context *m_storage_service_context;
diff --git a/deployments/component-test/component-test.cmake b/deployments/component-test/component-test.cmake
index 7c82cb7..e1855a3 100644
--- a/deployments/component-test/component-test.cmake
+++ b/deployments/component-test/component-test.cmake
@@ -69,8 +69,11 @@
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
 		"components/service/crypto/provider/serializer/packed-c"
+		"components/service/crypto/provider/extension/hash"
+		"components/service/crypto/provider/extension/hash/serializer/packed-c"
 		"components/service/crypto/provider/test"
 		"components/service/crypto/backend/mbedcrypto"
+		"components/service/crypto/factory/full"
 		"components/service/crypto/test/unit"
 		"components/service/crypto/test/service"
 		"components/service/crypto/test/service/protobuf"
diff --git a/deployments/crypto/opteesp/CMakeLists.txt b/deployments/crypto/opteesp/CMakeLists.txt
index ee2c3dc..cbc1d73 100644
--- a/deployments/crypto/opteesp/CMakeLists.txt
+++ b/deployments/crypto/opteesp/CMakeLists.txt
@@ -48,6 +48,9 @@
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
 		"components/service/crypto/provider/serializer/packed-c"
+		"components/service/crypto/provider/extension/hash"
+		"components/service/crypto/provider/extension/hash/serializer/packed-c"
+		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/platform"
 		"components/service/secure_storage/include"
diff --git a/deployments/crypto/opteesp/crypto_sp.c b/deployments/crypto/opteesp/crypto_sp.c
index bca971b..ce236d9 100644
--- a/deployments/crypto/opteesp/crypto_sp.c
+++ b/deployments/crypto/opteesp/crypto_sp.c
@@ -6,9 +6,7 @@
 
 #include <rpc/ffarpc/endpoint/ffarpc_call_ep.h>
 #include <service/secure_storage/factory/storage_factory.h>
-#include <service/crypto/provider/crypto_provider.h>
-#include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
-#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
 #include <service/crypto/backend/mbedcrypto/mbedcrypto_backend.h>
 #include <protocols/rpc/common/packed-c/status.h>
 #include <config/ramstore/config_ramstore.h>
@@ -27,7 +25,7 @@
 
 void __noreturn sp_main(struct ffa_init_info *init_info)
 {
-	struct crypto_provider crypto_provider;
+	struct crypto_provider *crypto_provider;
 	struct ffa_call_ep ffarpc_call_ep;
 	struct rpc_interface *crypto_iface;
 	struct sp_msg req_msg = { 0 };
@@ -47,15 +45,10 @@
 	/* Initialize the crypto service */
 	crypto_iface = NULL;
 
-    if (mbedcrypto_backend_init(storage_backend, 0) == PSA_SUCCESS) {
+	if (mbedcrypto_backend_init(storage_backend, 0) == PSA_SUCCESS) {
 
-        crypto_iface = crypto_provider_init(&crypto_provider);
-
-		crypto_provider_register_serializer(&crypto_provider,
-                    TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
-
-		crypto_provider_register_serializer(&crypto_provider,
-                    TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+		crypto_provider = crypto_provider_factory_create();
+		crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
 	}
 
 	ffa_call_ep_init(&ffarpc_call_ep, crypto_iface);
diff --git a/deployments/libts/linux-pc/CMakeLists.txt b/deployments/libts/linux-pc/CMakeLists.txt
index f8ab349..b4d39a1 100644
--- a/deployments/libts/linux-pc/CMakeLists.txt
+++ b/deployments/libts/linux-pc/CMakeLists.txt
@@ -57,6 +57,9 @@
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
 		"components/service/crypto/provider/serializer/packed-c"
+		"components/service/crypto/provider/extension/hash"
+		"components/service/crypto/provider/extension/hash/serializer/packed-c"
+		"components/service/crypto/factory/full"
 		"components/service/crypto/backend/mbedcrypto"
 		"components/service/crypto/backend/mbedcrypto/trng_adapter/linux"
 		"components/service/secure_storage/include"
diff --git a/deployments/se-proxy/opteesp/CMakeLists.txt b/deployments/se-proxy/opteesp/CMakeLists.txt
index 29d2edc..af25f39 100644
--- a/deployments/se-proxy/opteesp/CMakeLists.txt
+++ b/deployments/se-proxy/opteesp/CMakeLists.txt
@@ -60,6 +60,9 @@
 		"components/service/crypto/provider"
 		"components/service/crypto/provider/serializer/protobuf"
 		"components/service/crypto/provider/serializer/packed-c"
+		"components/service/crypto/provider/extension/hash"
+		"components/service/crypto/provider/extension/hash/serializer/packed-c"
+		"components/service/crypto/factory/full"
 		"components/service/secure_storage/include"
 		"components/service/secure_storage/frontend/secure_storage_provider"
 		"components/service/attestation/include"
diff --git a/deployments/se-proxy/opteesp/service_proxy_factory.c b/deployments/se-proxy/opteesp/service_proxy_factory.c
index 6bbee65..6261128 100644
--- a/deployments/se-proxy/opteesp/service_proxy_factory.c
+++ b/deployments/se-proxy/opteesp/service_proxy_factory.c
@@ -8,9 +8,7 @@
 #include <rpc/common/endpoint/rpc_interface.h>
 #include <service/attestation/provider/attest_provider.h>
 #include <service/attestation/provider/serializer/packed-c/packedc_attest_provider_serializer.h>
-#include <service/crypto/provider/crypto_provider.h>
-#include <service/crypto/provider/serializer/protobuf/pb_crypto_provider_serializer.h>
-#include <service/crypto/provider/serializer/packed-c/packedc_crypto_provider_serializer.h>
+#include <service/crypto/factory/crypto_provider_factory.h>
 #include <components/service/secure_storage/frontend/secure_storage_provider/secure_storage_provider.h>
 
 /* Not needed once proxy backends added */
@@ -74,19 +72,12 @@
 struct rpc_interface *crypto_proxy_create(void)
 {
 	struct rpc_interface *crypto_iface = NULL;
-
-	/* Static objects for proxy instance */
-	static struct crypto_provider crypto_provider;
+	struct crypto_provider *crypto_provider;
 
 	if (mbedcrypto_backend_init(shared_storage_backend, 0) == PSA_SUCCESS) {
 
-		crypto_iface = crypto_provider_init(&crypto_provider);
-
-		crypto_provider_register_serializer(&crypto_provider,
-					TS_RPC_ENCODING_PROTOBUF, pb_crypto_provider_serializer_instance());
-
-		crypto_provider_register_serializer(&crypto_provider,
-					TS_RPC_ENCODING_PACKED_C, packedc_crypto_provider_serializer_instance());
+		crypto_provider = crypto_provider_factory_create();
+		crypto_iface = service_provider_get_rpc_interface(&crypto_provider->base_provider);
 	}
 
 	return crypto_iface;