Add encrypted block store unit tests

Change-Id: I2ab20d23d2ec3fa14b33acc428f99757e27a9a38
Signed-off-by: Gabor Toth <gabor.toth2@arm.com>
diff --git a/components/service/block_storage/block_store/encrypted/unit/test_encrypted_block_store.cpp b/components/service/block_storage/block_store/encrypted/unit/test_encrypted_block_store.cpp
new file mode 100644
index 0000000..9e1709e
--- /dev/null
+++ b/components/service/block_storage/block_store/encrypted/unit/test_encrypted_block_store.cpp
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include <string.h>
+
+#include "encrypted_block_store.h"
+#include "mock_block_store.h"
+#include "mock_crypto.h"
+#include "mock_libc.h"
+#include "unit_test_utils.h"
+
+TEST_GROUP(EncryptedBlockStoreUnitTests)
+{
+	TEST_SETUP()
+	{
+		m_back_store = mock_block_store_init(&m_mock_store, &m_partition_guid, NUM_BLOCKS, BLOCK_SIZE);
+	}
+
+	TEST_TEARDOWN()
+	{
+		mock().checkExpectations();
+		mock().removeAllComparatorsAndCopiers();
+		mock().clear();
+	}
+
+	void set_expect_for_importing_root_key(void)
+	{
+		MOCK_IGNORE(psa_import_key);
+		MOCK_IGNORE(psa_reset_key_attributes);
+	}
+
+	void set_expect_key_derivation(size_t number_of_keys)
+	{
+		MOCK_IGNORE_NCALL(psa_key_derivation_setup, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_key_derivation_input_bytes, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_key_derivation_input_key, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_key_derivation_input_bytes, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_key_derivation_output_key, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_key_derivation_abort, number_of_keys);
+		MOCK_IGNORE_NCALL(psa_reset_key_attributes, number_of_keys);
+	}
+
+	void mock_init_store(void)
+	{
+		psa_status_t status = PSA_SUCCESS;
+
+		expect_psa_crypto_init(PSA_SUCCESS);
+		set_expect_for_importing_root_key();
+		set_expect_key_derivation(2);
+		MOCK_IGNORE(psa_destroy_key);
+		expect_block_store_get_partition_info(m_back_store, &m_partition_guid, &info,
+						      PSA_SUCCESS);
+		MOCK_IGNORE(block_store_open);
+
+		m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID,
+							   &m_partition_guid, m_back_store);
+		CHECK(m_block_store != NULL);
+
+		status = block_store_open(m_encrypted_store.back_store, CLIENT_ID,
+					  &m_partition_guid, &m_encrypted_store.back_store_handle);
+		LONGS_EQUAL(PSA_SUCCESS, status);
+	}
+
+	void mock_deinit_store(void)
+	{
+		mock().disable();
+		encrypted_block_store_deinit(&m_encrypted_store);
+		mock().enable();
+	}
+
+	/* Ignores specific calls in encrypt_block function and then returns */
+	void mock_ignore_encrypt_block(uint8_t stage = 255)
+	{
+		MOCK_TILL_STAGE(stage, 1, "psa_cipher_encrypt_setup", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 2, "psa_cipher_update",
+			.withOutputParameterReturning("output_length", &BLK_AES_BLOCK_SIZE,
+						       sizeof(BLK_AES_BLOCK_SIZE))
+			.ignoreOtherParameters());
+		/*
+		 * Encryption is always called with multiples of AES blocks, which will always be.
+		 * Full processed by the update call. Finish shall always provide 0 data length.
+		 */
+		MOCK_TILL_STAGE(stage, 3, "psa_cipher_finish",
+			.withOutputParameterReturning("output_length", &MOCK_NULL_SIZE,
+						       sizeof(MOCK_NULL_SIZE))
+			.ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 4, "psa_cipher_encrypt_setup", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 5, "psa_cipher_set_iv", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 6, "psa_cipher_update",
+			.withOutputParameterReturning("output_length", &BLOCK_SIZE,
+						       sizeof(BLOCK_SIZE))
+			.ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 7, "psa_cipher_finish",
+			.withOutputParameterReturning("output_length", &MOCK_NULL_SIZE,
+						       sizeof(MOCK_NULL_SIZE))
+			.ignoreOtherParameters());
+	}
+
+	/* Ignores specific calls in decrypt_block function and then returns */
+	void mock_ignore_decrypt_block(uint8_t stage = 255)
+	{
+		MOCK_TILL_STAGE(stage, 1, "psa_cipher_encrypt_setup", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 2, "psa_cipher_update",
+				.withOutputParameterReturning("output_length", &BLK_AES_BLOCK_SIZE,
+							      sizeof(BLK_AES_BLOCK_SIZE))
+					.ignoreOtherParameters());
+		/*
+		 * Decryption is always called with multiples of AES blocks, which will always be.
+		 * Full processed by the update call. Finish shall always provide 0 data length.
+		 */
+		MOCK_TILL_STAGE(stage, 3, "psa_cipher_finish",
+			.withOutputParameterReturning("output_length", &MOCK_NULL_SIZE,
+						       sizeof(MOCK_NULL_SIZE))
+			.ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 4, "psa_cipher_decrypt_setup", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 5, "psa_cipher_set_iv", .ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 6, "psa_cipher_update",
+			.withOutputParameterReturning("output_length", &BLOCK_SIZE,
+						       sizeof(BLOCK_SIZE))
+			.ignoreOtherParameters());
+		MOCK_TILL_STAGE(stage, 7, "psa_cipher_finish",
+			.withOutputParameterReturning("output_length", &MOCK_NULL_SIZE,
+						       sizeof(MOCK_NULL_SIZE))
+			.ignoreOtherParameters());
+	}
+
+	struct mock_block_store m_mock_store;
+	struct block_store *m_back_store;
+	struct block_store *m_block_store;
+	struct encrypted_block_store m_encrypted_store;
+	const uint32_t CLIENT_ID = 27;
+	const size_t BLOCK_SIZE = 512;
+	struct uuid_octets m_partition_guid = {
+		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+	};
+	storage_partition_handle_t m_handle = 1;
+	const uint64_t LBA = 2;
+	const size_t NUM_BLOCKS = 3;
+	psa_status_t m_status = PSA_SUCCESS;
+	struct storage_partition_info info = { NUM_BLOCKS, BLOCK_SIZE, { 0 }, { 0 } };
+	size_t BLK_AES_BLOCK_SIZE = 16;
+	size_t MOCK_NULL_SIZE = 0;
+};
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure__null_arguments)
+{
+	m_block_store =
+		encrypted_block_store_init(NULL, CLIENT_ID, &m_partition_guid, m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+
+	m_block_store =
+		encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, NULL, m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+
+	m_block_store =
+		encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid, NULL);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure__psa_crypto_init)
+{
+	expect_psa_crypto_init(PSA_ERROR_GENERIC_ERROR);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure__psa_import_key)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+
+	MOCK_IGNORE(psa_reset_key_attributes);
+	MOCK_RETVAL_ONLY(psa_import_key, PSA_ERROR_GENERIC_ERROR);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure_decrypt_key__psa_key_derivation_setup)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+
+	/* First derivation (encrypt key) fails */
+	MOCK_RETVAL_ONLY(psa_key_derivation_setup, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure__inbuffer_allocation)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(2);
+	MOCK_IGNORE(psa_destroy_key);
+	expect_block_store_get_partition_info(m_back_store, &m_partition_guid, &info, PSA_SUCCESS);
+
+	mock_libc_enable();
+	expect_calloc(NULL);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+
+	mock_libc_disable();
+
+	CHECK(m_block_store == NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure__outbuffer_allocation)
+{
+	uint8_t buffer[1] = { 0 };
+
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(2);
+	MOCK_IGNORE(psa_destroy_key);
+	expect_block_store_get_partition_info(m_back_store, &m_partition_guid, &info, PSA_SUCCESS);
+
+	mock_libc_enable();
+	expect_calloc(&buffer);
+	expect_calloc(NULL);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+
+	mock_libc_disable();
+
+	CHECK(m_block_store == NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_decrypt_key__psa_key_derivation_input_bytes_salt)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+
+	/* First derivation (encrypt key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_bytes, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_decrypt_key__psa_key_derivation_input_key)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+
+	/* First derivation (encrypt key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_key, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_decrypt_key__psa_key_derivation_input_bytes_info)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+
+	/* First derivation (encrypt key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_IGNORE(psa_key_derivation_input_key);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_bytes, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_decrypt_key__psa_key_derivation_output_key)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+
+	/* First derivation (encrypt key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_IGNORE(psa_key_derivation_input_key);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_RETVAL_ONLY(psa_key_derivation_output_key, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure_essiv_key__psa_key_derivation_setup)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(1);
+
+	/* Second derivation (essiv key) fails */
+	MOCK_RETVAL_ONLY(psa_key_derivation_setup, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_essiv_key__psa_key_derivation_input_bytes_salt)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(1);
+
+	/* Second derivation (essiv key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_bytes, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure_essiv_key__psa_key_derivation_input_key)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(1);
+
+	/* Second derivation (essiv key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_key, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_essiv_key__psa_key_derivation_input_bytes_info)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(1);
+
+	/* Second derivation (essiv key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_IGNORE(psa_key_derivation_input_key);
+	MOCK_RETVAL_ONLY(psa_key_derivation_input_bytes, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_essiv_key__psa_key_derivation_output_key)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(1);
+
+	/* Second derivation (essiv key) fails */
+	MOCK_IGNORE(psa_key_derivation_setup);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_IGNORE(psa_key_derivation_input_key);
+	MOCK_IGNORE(psa_key_derivation_input_bytes);
+	MOCK_RETVAL_ONLY(psa_key_derivation_output_key, PSA_ERROR_GENERIC_ERROR);
+	MOCK_IGNORE(psa_key_derivation_abort);
+	MOCK_IGNORE(psa_reset_key_attributes);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_init_failure_essiv_key__block_store_get_partition_info)
+{
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(2);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	MOCK_RETVAL_ONLY(block_store_get_partition_info, PSA_ERROR_GENERIC_ERROR);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	UNSIGNED_LONGLONGS_EQUAL(m_block_store, NULL);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_init_failure_essiv_key__block_store_open)
+{
+	psa_status_t status = PSA_SUCCESS;
+
+	expect_psa_crypto_init(PSA_SUCCESS);
+	set_expect_for_importing_root_key();
+	set_expect_key_derivation(2);
+
+	/* Root key is destroyed */
+	MOCK_IGNORE(psa_destroy_key);
+
+	MOCK_IGNORE(block_store_get_partition_info);
+
+	MOCK_RETVAL_ONLY(block_store_open, PSA_ERROR_GENERIC_ERROR);
+
+	m_block_store = encrypted_block_store_init(&m_encrypted_store, CLIENT_ID, &m_partition_guid,
+						   m_back_store);
+	CHECK(m_block_store != NULL);
+
+	status = block_store_open(m_encrypted_store.back_store, CLIENT_ID, &m_partition_guid,
+				  &m_encrypted_store.back_store_handle);
+	LONGS_EQUAL(PSA_ERROR_GENERIC_ERROR, status);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_deinit)
+{
+	mock_init_store();
+
+	MOCK_IGNORE(block_store_close);
+
+	/* Both derived keys shall be destroyed */
+	MOCK_IGNORE_NCALL(psa_destroy_key, 2);
+
+	encrypted_block_store_deinit(&m_encrypted_store);
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_open)
+{
+	mock_init_store();
+
+	/* Verify of block_store_open called through m_block_store calls the relevant API of the back store */
+	expect_block_store_open(m_encrypted_store.back_store, CLIENT_ID, &m_partition_guid,
+				&m_handle, PSA_ERROR_GENERIC_ERROR);
+	m_status = block_store_open(m_block_store, CLIENT_ID, &m_partition_guid,
+						  &m_handle);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_close)
+{
+	mock_init_store();
+
+	/* Verify of block_store_close called through m_block_store calls the relevant API of the back store */
+	expect_block_store_close(m_encrypted_store.back_store, CLIENT_ID, m_handle,
+				 PSA_ERROR_GENERIC_ERROR);
+	m_status = block_store_close(m_block_store, CLIENT_ID, m_handle);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_erase)
+{
+	mock_init_store();
+
+	/* Verify of block_store_erase called through m_block_store calls the relevant API of the back store */
+	expect_block_store_erase(m_encrypted_store.back_store, CLIENT_ID, m_handle, LBA, NUM_BLOCKS,
+				 PSA_ERROR_GENERIC_ERROR);
+	m_status = block_store_erase(m_block_store, CLIENT_ID, m_handle, LBA,
+						   NUM_BLOCKS);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__block_store_read)
+{
+	size_t data_len = 0;
+
+	mock_init_store();
+
+	/*
+	 * As a reasult of AES CBC whole block needs to be read or written, even if only a small part is requested.
+	 * buffer argument is irrelevant, because the data is read into a local temporary buffer before decryption.
+	 */
+	mock().expectOneCall("block_store_read")
+		.withUnsignedIntParameter("client_id", CLIENT_ID)
+		.withUnsignedIntParameter("handle", m_handle)
+		.withUnsignedIntParameter("lba", LBA)
+		.withUnsignedIntParameter("offset", 0)
+		.withUnsignedIntParameter("buffer_size", BLOCK_SIZE)
+		.withOutputParameterReturning("data_len", &data_len, sizeof(data_len))
+		.andReturnValue(PSA_ERROR_GENERIC_ERROR)
+		.ignoreOtherParameters();
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE / 2, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__partial_read)
+{
+	size_t data_len = BLOCK_SIZE - 1;
+
+	mock_init_store();
+
+	/* Only some part of the requested data is provided by the store */
+	mock().expectOneCall("block_store_read")
+		.withUnsignedIntParameter("client_id", CLIENT_ID)
+		.withUnsignedIntParameter("handle", m_handle)
+		.withUnsignedIntParameter("lba", LBA)
+		.withUnsignedIntParameter("offset", 0)
+		.withUnsignedIntParameter("buffer_size", BLOCK_SIZE)
+		.withOutputParameterReturning("data_len", &data_len, sizeof(data_len))
+		.andReturnValue(PSA_SUCCESS)
+		.ignoreOtherParameters();
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE / 2, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_INSUFFICIENT_DATA);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure_calc_essiv__psa_cipher_encrypt_setup)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	MOCK_UINT_PARAMETER_RETVAL(psa_cipher_encrypt_setup, alg, PSA_ALG_ECB_NO_PADDING, PSA_ERROR_GENERIC_ERROR);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure_calc_essiv__psa_cipher_update)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(1);
+
+	MOCK_RETVAL_ONLY(psa_cipher_update, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_read_failure_calc_essiv__psa_cipher_finish_return_error)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(2);
+
+	MOCK_RETVAL_ONLY(psa_cipher_finish, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_read_failure_calc_essiv__psa_cipher_finish_length_error)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(2);
+
+	MOCK_OUTPUT_PARAMETER_ONLY(psa_cipher_finish, output_length, BLK_AES_BLOCK_SIZE);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__psa_cipher_decrypt_setup)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(3);
+
+	/* Decrypt data read */
+	MOCK_RETVAL_ONLY(psa_cipher_decrypt_setup, PSA_ERROR_GENERIC_ERROR);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__psa_cipher_set_iv)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(4);
+
+	MOCK_RETVAL_ONLY(psa_cipher_set_iv, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__psa_cipher_update)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(5);
+
+	MOCK_RETVAL_ONLY(psa_cipher_update, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__psa_cipher_finish_return_error)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(6);
+
+	MOCK_RETVAL_ONLY(psa_cipher_finish, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_read_failure__psa_cipher_finish_length_error)
+{
+	size_t data_len = BLOCK_SIZE;
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block(6);
+
+	MOCK_OUTPUT_PARAMETER_ONLY(psa_cipher_finish, output_length, BLK_AES_BLOCK_SIZE);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_read(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						  BLOCK_SIZE, NULL, &data_len);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__block_store_read)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_RETVAL(block_store_read, data_len, data_len, PSA_ERROR_GENERIC_ERROR);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__partial_read)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE - 1;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	/* Only some part of the requested data is provided by the store */
+	MOCK_OUTPUT_PARAMETER_RETVAL(block_store_read, data_len, data_len, PSA_SUCCESS);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_INSUFFICIENT_DATA);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure_calc_essiv__psa_cipher_encrypt_setup)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+
+	MOCK_UINT_PARAMETER_RETVAL(psa_cipher_encrypt_setup, alg, PSA_ALG_ECB_NO_PADDING, PSA_ERROR_GENERIC_ERROR);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure_calc_essiv__psa_cipher_update)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(1);
+
+	MOCK_RETVAL_ONLY(psa_cipher_update, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_write_failure_calc_essiv__psa_cipher_finish_return_error)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(2);
+
+	MOCK_RETVAL_ONLY(psa_cipher_finish, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests,
+     block_store_write_failure_calc_essiv__psa_cipher_finish_length_error)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(2);
+
+	MOCK_OUTPUT_PARAMETER_ONLY(psa_cipher_finish, output_length, BLK_AES_BLOCK_SIZE);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__psa_cipher_encrypt_setup)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(3);
+
+	mock().expectOneCall("psa_cipher_encrypt_setup")
+		.withUnsignedIntParameter("alg", PSA_ALG_CBC_NO_PADDING)
+		.andReturnValue(PSA_ERROR_GENERIC_ERROR)
+		.ignoreOtherParameters();
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__psa_cipher_set_iv)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(4);
+
+	MOCK_RETVAL_ONLY(psa_cipher_set_iv, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__psa_cipher_update)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(5);
+
+	MOCK_RETVAL_ONLY(psa_cipher_update, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__psa_cipher_finish_return_error)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(6);
+
+	MOCK_RETVAL_ONLY(psa_cipher_finish, PSA_ERROR_GENERIC_ERROR);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__psa_cipher_finish_length_error)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block(6);
+
+	MOCK_OUTPUT_PARAMETER_ONLY(psa_cipher_finish, output_length, BLK_AES_BLOCK_SIZE);
+
+	MOCK_IGNORE(psa_cipher_abort);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__block_store_write)
+{
+	size_t num_written = BLOCK_SIZE;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block();
+
+	MOCK_RETVAL_ONLY(block_store_write, PSA_ERROR_GENERIC_ERROR);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_GENERIC_ERROR);
+
+	mock_deinit_store();
+}
+
+TEST(EncryptedBlockStoreUnitTests, block_store_write_failure__partial_write)
+{
+	size_t num_written = BLOCK_SIZE - 1;
+	size_t data_len = BLOCK_SIZE;
+	uint8_t data[BLOCK_SIZE] = { 0 };
+
+	mock_init_store();
+
+	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+
+	mock_ignore_decrypt_block();
+	mock_ignore_encrypt_block();
+
+	MOCK_OUTPUT_PARAMETER_RETVAL(block_store_write, num_written, num_written, PSA_SUCCESS);
+
+	m_status = block_store_write(m_block_store, CLIENT_ID, m_handle, LBA, 0,
+						   data, BLOCK_SIZE, &num_written);
+	UNSIGNED_LONGLONGS_EQUAL(m_status, PSA_ERROR_INSUFFICIENT_DATA);
+
+	mock_deinit_store();
+}
diff --git a/components/service/block_storage/block_store/encrypted/unit/tests.cmake b/components/service/block_storage/block_store/encrypted/unit/tests.cmake
new file mode 100644
index 0000000..8b0f608
--- /dev/null
+++ b/components/service/block_storage/block_store/encrypted/unit/tests.cmake
@@ -0,0 +1,47 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include(UnitTest)
+
+unit_test_add_suite(
+	NAME encrypted_block_store
+	SOURCES
+		${UNIT_TEST_PROJECT_PATH}/components/service/block_storage/block_store/encrypted/encrypted_block_store.c
+		${UNIT_TEST_PROJECT_PATH}/components/service/block_storage/block_store/block_store.c
+		${UNIT_TEST_PROJECT_PATH}/components/service/block_storage/block_store/device/mock/mock_block_store.cpp
+		${UNIT_TEST_PROJECT_PATH}/components/service/crypto/mock/mock_crypto.cpp
+		${UNIT_TEST_PROJECT_PATH}/components/common/libc/mock/mock_libc.cpp
+		${CMAKE_CURRENT_LIST_DIR}/test_encrypted_block_store.cpp
+	INCLUDE_DIRECTORIES
+		${UNIT_TEST_PROJECT_PATH}
+		${UNIT_TEST_PROJECT_PATH}/deployments/unit-tests/include
+		${UNIT_TEST_PROJECT_PATH}/components/service/block_storage/block_store/encrypted
+		${UNIT_TEST_PROJECT_PATH}/components/service/block_storage/block_store/device/mock
+		${UNIT_TEST_PROJECT_PATH}/components/service/crypto/mock
+		${UNIT_TEST_PROJECT_PATH}/components/service/crypto/include
+		${UNIT_TEST_PROJECT_PATH}/components/common/libc/mock
+		${UNIT_TEST_PROJECT_PATH}/components
+		${UNIT_TEST_PROJECT_PATH}/components/service/common/include
+	COMPILE_DEFINITIONS
+		-DARM64
+)
+
+# To test if the component handles memory allocation errors properly, the calloc function will be replaced with a custom function
+set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/../encrypted_block_store.c PROPERTIES
+	COMPILE_DEFINITIONS calloc=MOCK_CALLOC
+)
+
+target_compile_definitions(encrypted_block_store PRIVATE
+	"TRACE_PREFIX=UT"
+	"TRACE_LEVEL=0"
+)
+
+add_components(TARGET encrypted_block_store
+	BASE_DIR ${TS_ROOT}
+	COMPONENTS
+		"components/common/trace"
+		"components/common/utils"
+)
\ No newline at end of file
diff --git a/deployments/unit-tests/include/unit_test_utils.h b/deployments/unit-tests/include/unit_test_utils.h
new file mode 100644
index 0000000..f5430d2
--- /dev/null
+++ b/deployments/unit-tests/include/unit_test_utils.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef UNIT_TEST_UTILS_H
+#define UNIT_TEST_UTILS_H
+
+/*
+ * Add an expectOneCall() expectation with the defined "chained arguments" and return
+ * from the function if variable matches "stage". The macro allows defining all
+ * expectations for a test subject function in a single mocking function. The stage
+ * enables conditionally disabling expectations to match the point where the test subject
+ * will return with an error. This avoids setting unmeet expectations and removes test
+ * code duplication.
+ *
+ * Example usage (so not use apostrophes in the last argument!):
+ * 	MOCK_TILL_STAGE(variable, 1, "psa_cipher_encrypt_setup", .ignoreOtherParameters());
+ */
+#define MOCK_TILL_STAGE(variable, stage, function, chained_args)    \
+	do {                                                        \
+		if ((variable) >= (stage))                          \
+			mock().expectOneCall(function)chained_args; \
+	} while (0)
+
+/*
+ * Ignores all parameters of the mocked function
+ * Example usage:
+ * 	MOCK_IGNORE(psa_destroy_key)
+ */
+#define MOCK_IGNORE(func) mock().expectOneCall(#func).ignoreOtherParameters()
+
+/*
+ * Ignores all parameters of the mocked function and expects N calls
+ * Example usage:
+ * 	MOCK_IGNORE(psa_destroy_key, 5)
+ */
+#define MOCK_IGNORE_NCALL(func, N) mock().expectNCalls(N, #func).ignoreOtherParameters()
+
+/*
+ * Ignores all parameters of the mocked function, but returns the specified value
+ * Example usage:
+ * 	MOCK_RETVAL_ONLY(psa_destroy_key, PSA_ERROR_GENERIC_ERROR)
+ */
+#define MOCK_RETVAL_ONLY(func, retval) mock().expectOneCall(#func).andReturnValue(retval).ignoreOtherParameters()
+
+/*
+ * Ignores all parameters of the mocked function, except an output parameter
+ * Example usage:
+ * 	MOCK_OUTPUT_PARAMETER_ONLY(block_store_read, data_len, data_len);
+ */
+#define MOCK_OUTPUT_PARAMETER_ONLY(func, parameter, variable) mock().expectOneCall(#func).withOutputParameterReturning(#parameter, &variable, sizeof(variable)).ignoreOtherParameters()
+
+/*
+ * Ignores all parameters of the mocked function, except an output parameter and returns value
+ * Example usage:
+ * 	MOCK_OUTPUT_PARAMETER_RETVAL(block_store_write, num_written, num_written, PSA_ERROR_GENERIC_ERROR);
+ */
+#define MOCK_OUTPUT_PARAMETER_RETVAL(func, parameter, variable, retval) mock().expectOneCall(#func).withOutputParameterReturning(#parameter, &variable, sizeof(variable)).andReturnValue(retval).ignoreOtherParameters()
+
+/*
+ * Ignores all parameters of the mocked function, except an unsigned int paramter and returns value
+ * Example usage:
+ * 	MOCK_UINT_PARAMETER_RETVAL(psa_cipher_encrypt_setup, alg, PSA_ALG_ECB_NO_PADDING, PSA_ERROR_GENERIC_ERROR);
+ */
+#define MOCK_UINT_PARAMETER_RETVAL(func, parameter, value, retval) mock().expectOneCall(#func).withUnsignedIntParameter(#parameter, value).andReturnValue(retval).ignoreOtherParameters()
+
+#endif /* UNIT_TEST_UTILS_H */
diff --git a/deployments/unit-tests/linux-pc/CMakeLists.txt b/deployments/unit-tests/linux-pc/CMakeLists.txt
index 3bb6d83..d90716c 100644
--- a/deployments/unit-tests/linux-pc/CMakeLists.txt
+++ b/deployments/unit-tests/linux-pc/CMakeLists.txt
@@ -56,3 +56,4 @@
 include(${TS_ROOT}/components/rpc/common/tests.cmake)
 include(${TS_ROOT}/components/rpc/mm_communicate/endpoint/sp/tests.cmake)
 include(${TS_ROOT}/components/service/uefi/smm_variable/frontend/mm_communicate/tests.cmake)
+include(${TS_ROOT}/components/service/block_storage/block_store/encrypted/unit/tests.cmake)