#include <stdio.h>
#include <string.h>

#include "vk_interface.h"
#include "vk_data_struct.h"
#include "vk_constants.h"
#include "vk_error.h"
#include "vk_log.h"
#include "vk_table.h"
#include "vk_utils.h"
#include "vk_vault_manager.h"

#include "crypto/vk_crypto_aes.h"
#include "crypto/vk_crypto.h"

extern vk_device_info_t g_device_info;

// Description
// Rev 01
//   Change Vault structure
//   - Define two vault type only for steady, rpmb used.
//   - Use random IV for encryption
int recovery_cass_legacy(target_t* target, cmd_req_t* req, uint8_t* source, uint8_t* legacy_vault, int legacy_level)
{
	int ret = VK_ERR_GENERAL;

	uint8_t* source_buf = NULL;
	uint8_t* buf = NULL;
	uint32_t buf_len = 0;
	uint32_t sheltered_vault_len = 0;
	uint32_t stored_sheltered_data_size = 0;
	uint8_t tag[AES_GCM_TAG_LEN] = {0,};
	uint32_t tag_len = 0;
	uint8_t random_iv[AES_IV_LEN] = {0,};
	const uint32_t old_cc = 0xFAC2BB01;

	if (source == NULL) {
		return VK_ERR_GENERAL;
	}

	if (legacy_vault == NULL) {
		return VK_ERR_GENERAL;
	}

	ret = target->platform.memory_alloc(&source_buf, MAX_VAULT_LEN);
	if (ret != VK_SUCCESS || source_buf == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		return ret;
	}

	ret = target->platform.memory_alloc(&buf, MAX_VAULT_LEN);
	if (ret != VK_SUCCESS || buf == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		goto out;
	}

	memcpy(source_buf, source, MAX_VAULT_LEN);
	memset(legacy_vault, 0, MAX_VAULT_LEN);

	// get iv
	memcpy(random_iv, req->random_iv, AES_IV_LEN);

	// Unwrap sheltered vault
	if (!isAllZero(source_buf + VAULT_SINGLE_BLOCK_LEN, 32)) {
		memcpy(&stored_sheltered_data_size, source_buf + SHELTERED_VAULT_DATA_LEN_OFFSET, SHELTERED_VAULT_DATA_LEN_SIZE);
		memcpy(tag, source_buf + AES_GCM_TAG_OFFSET, AES_GCM_TAG_LEN);
		memcpy(random_iv, source_buf + AES_IV_OFFSET, AES_IV_LEN);

		if (stored_sheltered_data_size > MAX_SHELTERED_DATA_LEN) {
			LOGE("%s: Invalid stored sheltered data size(%d)\n", __func__, stored_sheltered_data_size);
			ret = VK_ERR_INVALID_ARGUMENT;
			goto out;
		}

		sheltered_vault_len = 96 + stored_sheltered_data_size;

		ret = vk_crypto_aes_256_gcm_decrypt(source_buf + VAULT_SINGLE_BLOCK_LEN, sheltered_vault_len,
				buf, &buf_len, tag, AES_GCM_TAG_LEN, NULL, random_iv);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed to decrypt with aes gcm(%d/%u/%u)\n", __func__, ret, sheltered_vault_len, buf_len);
			goto out;
		}

		if (sheltered_vault_len != buf_len) {
			LOGE("%s: Unexpected plaintext length(%u/%u)\n", __func__, sheltered_vault_len, buf_len);
			ret = VK_ERR_WRAP_UNWRAP_OBJECT;
			goto out;
		}
		memcpy(source_buf + VAULT_SINGLE_BLOCK_LEN, buf, buf_len);
	} else {
		LOGE("%s: Break CASS Vault\n", __func__);
		ret = VK_ERR_GENERAL;
		goto out;
	}

	// Making legacy vault
	if (legacy_level == 1) {
		memcpy(legacy_vault, source_buf, 16);
		memcpy(legacy_vault + 16 + 124, source_buf + VAULT_KEY_OFFSET, VAULT_KEY_LEN);
		memcpy(legacy_vault + (256 - 32 - 4), &old_cc, sizeof(uint32_t));
	} else {
		memcpy(legacy_vault, source_buf, 32);
		memcpy(legacy_vault + 32, random_iv, AES_IV_LEN);
		memcpy(legacy_vault + 32 + 16 + 92, source_buf + VAULT_KEY_OFFSET, VAULT_KEY_LEN);
		memcpy(legacy_vault + (256 - 32 - 4), &old_cc, sizeof(uint32_t));
	}

	memset(buf, 0, MAX_VAULT_LEN);
	buf_len = 0;
	memset(tag, 0, AES_GCM_TAG_LEN);
	tag_len = AES_GCM_TAG_LEN;

	// wrapping unsheltered vault
	if (legacy_level == 1) {
		ret = VK_GET_SECURE_ITEM(VK_SECURE_ITEM_LEGACY_FIXED_IV, random_iv, AES_IV_LEN);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed VK_GET_SECURE_ITEM(%d/%d)\n", __func__, VK_SECURE_ITEM_LEGACY_FIXED_IV, ret);
			goto out;
		}

		ret = vk_crypto_aes_256_gcm_encrypt(legacy_vault + 16,  124 + 32 + 32, buf, &buf_len, tag, tag_len, NULL, random_iv);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed to encrypt with aes gcm(%d/%u/%u)\n", __func__, ret, 124 + 32 + 32, buf_len);
			goto out;
		}

		if ((124 + 32 + 32) != buf_len) {
			LOGE("%s: Unexpected ciphertext length(%u/%u)\n", __func__, 124 + 32 + 32, buf_len);
			ret = VK_ERR_WRAP_UNWRAP_OBJECT;
			goto out;
		}
		memcpy(legacy_vault + 16, buf, buf_len);
	} else {
		ret = vk_crypto_aes_256_gcm_encrypt(legacy_vault + 32 + 16,  92 + 32 + 32, buf, &buf_len, tag, tag_len, NULL, random_iv);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed to encrypt with aes gcm(%d/%u/%u)\n", __func__, ret, 92 + 32 + 32, buf_len);
			goto out;
		}

		if ((92 + 32 + 32) != buf_len) {
			LOGE("%s: Unexpected ciphertext length(%u/%u)\n", __func__, 92 + 32 + 32, buf_len);
			ret = VK_ERR_WRAP_UNWRAP_OBJECT;
			goto out;
		}
		memcpy(legacy_vault + 32 + 16, buf, buf_len);
	}
	// copy auth tag
	memcpy(legacy_vault + (256 - 32 - 4 - 16), tag, AES_GCM_TAG_LEN);
	// hashing unsheltered vault
	ret = vk_crypto_sha256(legacy_vault, HASHING_LEN, legacy_vault + (256 - 32));
	if (ret != VK_SUCCESS) {
		LOGE("%s: Failed to hash vault(%d)\n", __func__, ret);
		goto out;
	}

	memset(buf, 0, MAX_VAULT_LEN);
	buf_len = 0;
	memset(tag, 0, AES_GCM_TAG_LEN);
	tag_len = AES_GCM_TAG_LEN;

	// wrapping sheltered vault
	if (stored_sheltered_data_size > 0) {
		memcpy(legacy_vault + 256 + 32 + 4 + 16 + 4, source_buf + SHELTERED_DATA_OFFSET, stored_sheltered_data_size);
		ret = vk_crypto_aes_256_gcm_encrypt(legacy_vault + 256 + 32 + 4 + 16, 81 * 256 - 32 - 4 - 16,
					buf, &buf_len, tag, tag_len, NULL, random_iv);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed to encrypt with aes gcm(%d/%u/%u)\n", __func__, ret, stored_sheltered_data_size + 4, buf_len);
			goto out;
		}

		if ((81 * 256 - 32 - 4 - 16) != buf_len) {
			LOGE("%s: Unexpected ciphertext length(%u/%u)\n", __func__, 81 * 256 - 32 - 4 - 16, buf_len);
			ret = VK_ERR_WRAP_UNWRAP_OBJECT;
			goto out;
		}
		memcpy(legacy_vault + 256 + 32, &old_cc, sizeof(uint32_t));
		memcpy(legacy_vault + 256 + 32 + 4, tag, AES_GCM_TAG_LEN);
		memcpy(legacy_vault + 256 + 32 + 4 + 16, buf, buf_len);

		// hashing sheltered vault
		ret = vk_crypto_sha256(legacy_vault + 256 + 32, 81 * 256 - 32, legacy_vault + 256);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed to hash vault(%d)\n", __func__, ret);
			goto out;
		}
	}

out:
	if (source_buf != NULL) {
		memset(source_buf, 0, MAX_VAULT_LEN);
		target->platform.memory_free(source_buf);
	}

	if (buf != NULL) {
		memset(buf, 0, MAX_VAULT_LEN);
		target->platform.memory_free(buf);
	}

	return ret;	
}

int write_cass_vault_legacy(target_t* target, cmd_req_t* req, uint8_t* vault)
{
#if defined(VK_QSEE_SDM429) || defined(NO_NEED_TO_MIGRATION01)
	return VK_SUCCESS;
#endif
	int ret = VK_ERR_GENERAL;
	uint32_t i = 0;

	uint32_t client_code = 0;
	uint32_t old_client_code = 0;
	uint32_t magic = 0;

	uint32_t write_cnt, write_cnt_extra;
	uint32_t stored_sheltered_data_size = 0;
	uint32_t sheltered_vault_size = 0;
	uint8_t unsheltered_vault[VAULT_SINGLE_BLOCK_LEN] = {0,};
	uint8_t legacy_meta_170[VAULT_SINGLE_BLOCK_LEN] = {0,};

	uint8_t* pTemp = NULL;
	uint8_t* legacy_vault = NULL;

	const uint32_t cass_legacy_rpmb_index = 6;
	const uint32_t cass_legacy_rpmb_index_backup = 88;

	int android_first_api_level = 0;

	if (target == NULL) {
		LOGE("%s: target is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (req == NULL) {
		LOGE("%s: req is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (vault == NULL) {
		LOGE("%s: vault is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	android_first_api_level = getPropResult(PROP_TYPE_FIRST_API_LEVEL);
	if (android_first_api_level == PROP_RESULT_FALSE || android_first_api_level < 0) { // 'PROP_RESULT_FALSE' means getting failure of property value
		LOGE("%s: Failed to get prop result(%d/%d)\n", __func__, PROP_TYPE_FIRST_API_LEVEL, android_first_api_level);
		return VK_ERR_GENERAL;
	}

	if (android_first_api_level >= ANDROID_OS_Q) {
		// Skip write_cass_vault_legacy()
		return VK_SUCCESS;
	}

	write_cnt = write_cnt_extra = 0;

	if (g_device_info.rpmb_key_provisioning == 'T') {
		ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
			                        cass_legacy_rpmb_index, unsheltered_vault, VAULT_RPMB_BLOCK_UNIT);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Something went wrong while reading RPMB(%d)\n", __func__, ret);
			goto out;
		}

		if (isAllZero(unsheltered_vault, VAULT_SINGLE_BLOCK_LEN)) {
			goto out;
		}

		memcpy(&client_code, unsheltered_vault + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
		memcpy(&magic, unsheltered_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
		old_client_code = 0xFAC2BB01;

		// Making VK3.1 vault
		if (magic == old_client_code && client_code != VTAB[req->vtab_index].client_code) {
			ret = target->platform.memory_alloc(&legacy_vault, MAX_VAULT_LEN);
			if (ret != VK_SUCCESS || legacy_vault == NULL) {
				LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
				goto out;
			}

			ret = recovery_cass_legacy(target, req, vault, legacy_vault, 2);
			if (ret != VK_SUCCESS) goto out;

			// Write meta data in legacy meta (rpmb index 170)
			memcpy(legacy_meta_170, vault + VAULT_META_OFFSET, VAULT_META_LEN);

			ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition, 170, legacy_meta_170, 1);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while writing vault 170(%d)\n", __func__, ret);
				goto out;
			}

			sheltered_vault_size = (VTAB[req->vtab_index].num_blocks - 1) * VAULT_SINGLE_BLOCK_LEN;
			pTemp = legacy_vault;
		} else {
			memcpy(&stored_sheltered_data_size, unsheltered_vault + SHELTERED_VAULT_DATA_LEN_OFFSET, SHELTERED_VAULT_DATA_LEN_SIZE);

			if (stored_sheltered_data_size > MAX_SHELTERED_DATA_LEN) {
				LOGE("%s: Invalid stored sheltered data size(%d)\n", __func__, stored_sheltered_data_size);
				ret = VK_ERR_INVALID_ARGUMENT;
				goto out;
			}

			sheltered_vault_size = VAULT_KEY_LEN + VAULT_KEY_LEN + SHELTERED_RESERVED + stored_sheltered_data_size;
			pTemp = vault;
		}

#ifdef VK_RPMB_TRANSFER_MLT_BLK
		write_cnt = (uint32_t)((float)(sheltered_vault_size + VAULT_SINGLE_BLOCK_LEN) / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE));
		if (VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size != (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) {
			write_cnt_extra = (uint32_t)(((float)(VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size - (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) /  VAULT_SINGLE_BLOCK_LEN) + 0.999999);
		} else {
			write_cnt_extra = 0;
		}
#else
		write_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE) + 0.999999) + 1;
#endif
		for (i = 0; i < write_cnt; i++) {
			ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
				                         cass_legacy_rpmb_index_backup + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while writing mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
				goto out;
			}
			pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
		}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
		if (write_cnt_extra) {
			ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
				                         cass_legacy_rpmb_index_backup + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while writing extra mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
				goto out;
			}
		}
#endif
		if (magic == old_client_code && client_code != VTAB[req->vtab_index].client_code)
			pTemp = legacy_vault;
		else
			pTemp = vault;

		for (i = 0; i < write_cnt; i++) {
			ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
				                         cass_legacy_rpmb_index + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while writing vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
				goto out;
			}
			pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
		}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
		if (write_cnt_extra) {
			ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
				                         cass_legacy_rpmb_index + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while writing extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
				goto out;
			}
		}
#endif
		ret = VK_SUCCESS;
	}

out:
	memset(unsheltered_vault, 0, VAULT_SINGLE_BLOCK_LEN);

	if (legacy_vault != NULL) {
		memset(legacy_vault, 0, MAX_VAULT_LEN);
		target->platform.memory_free(legacy_vault);
	}

	LOGI("%s : write_cass_vault_legacy done\n", __func__);

	return ret;
}

int vk_migration_01(target_t* target, cmd_req_t* req, cmd_rsp_t* rsp)
{
#if defined(VK_QSEE_SDM429) || defined(NO_NEED_TO_MIGRATION01)
	return VK_SUCCESS;
#endif

	int ret = VK_ERR_GENERAL;
	uint32_t i = 0;

	int write_vault_level = 0;
	int cass_write_vault_level = 0;
	uint32_t read_cnt, read_cnt_extra, write_cnt, write_cnt_extra;

	uint8_t* client_stored_vault = NULL;
	uint8_t meta_vault[256] = {0,};
	uint32_t meta_vault_index = 0;	
	uint8_t stored_gcm_tag[AES_GCM_TAG_LEN] = {0,};
	uint8_t stored_iv[AES_IV_LEN] = {0,};
	uint32_t stored_sheltered_data_size = 0;
	uint32_t buf_len = 0;
	uint8_t* buf = NULL;
	uint8_t* pTemp = NULL;

	uint32_t client_code = 0;
	uint32_t old_client_code = 0;
	uint32_t magic = 0;

	uint32_t unsheltered_enc_offset = 0;
	uint32_t unsheltered_enc_size = 0;
	uint32_t sheltered_enc_offset = 0;
	uint32_t sheltered_enc_size = 0;

	// for KG
	int rpmb_start_index = 0;

	// Legacy VAULT item
	uint8_t* legacy_client_vault = NULL;

	// New VAULT item
	vault_t* new_client_vault = NULL;
	uint8_t new_unsheltered_data[MAX_UNSHELTERED_DATA_LEN] = {0,};
	uint32_t new_sheltered_data_size = 0;
	uint32_t new_client_code = 0;
	uint8_t new_iv[AES_IV_LEN] = {0,};
	uint8_t new_meta[VAULT_META_LEN] = {0,};
	uint8_t new_key[VAULT_KEY_LEN] = {0,};
	uint8_t new_key2[VAULT_KEY_LEN] = {0,};
	uint32_t sheltered_vault_size = 0;

	const uint32_t cass_legacy_rpmb_index = 6;
	const uint32_t cass_legacy_rpmb_index_backup = 88;

	int android_first_api_level = 0;

	if (target == NULL) {
		LOGE("%s: target is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	if (req == NULL) {
		LOGE("%s: req is null\n", __func__);
		return VK_ERR_INVALID_ARGUMENT;
	}

	android_first_api_level = getPropResult(PROP_TYPE_FIRST_API_LEVEL);
	if (android_first_api_level == PROP_RESULT_FALSE || android_first_api_level < 0) { // 'PROP_RESULT_FALSE' means getting failure of property value
		LOGE("%s: Failed to get prop result(%d/%d)\n", __func__, PROP_TYPE_FIRST_API_LEVEL, android_first_api_level);
		return VK_ERR_GENERAL;
	}

	if (android_first_api_level >= ANDROID_OS_Q) {
		// Skip vk_migration_01()
		return VK_SUCCESS;
	}

	read_cnt = read_cnt_extra = write_cnt = write_cnt_extra = 0;

	ret = target->platform.memory_alloc(&client_stored_vault, MAX_VAULT_LEN);
	if (ret != VK_SUCCESS || client_stored_vault == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		goto out;
	}

	ret = target->platform.memory_alloc(&legacy_client_vault, MAX_VAULT_LEN);
	if (ret != VK_SUCCESS || legacy_client_vault == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		goto out;
	}

	if (!strncmp(VTAB[req->vtab_index].vault_name, VAULT_NAME_CASS, sizeof(VAULT_NAME_CASS))) {
		if (g_device_info.rpmb_key_provisioning == 'T') {
			ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
				                        VTAB[req->vtab_index].start_index_rpmb, client_stored_vault, VAULT_RPMB_BLOCK_UNIT);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
				goto out;
			}

			if (isAllZero(client_stored_vault, VAULT_SINGLE_BLOCK_LEN)) {
LOGI("SEQ 1\n");
				// Read legacy vault
				ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
					                        cass_legacy_rpmb_index, client_stored_vault, VAULT_RPMB_BLOCK_UNIT);
				if (ret != VK_SUCCESS) {
					LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
					goto out;
				}

				if (isAllZero(client_stored_vault, VAULT_SINGLE_BLOCK_LEN)) {
LOGI("SEQ 2\n");
					// check steady
					if (req->preload == NULL || req->preload_size == 0 || req->preload_size > req->entire_vault_size) {
						LOGE("%s: Invalid argument (preload)\n", __func__);
						ret = VK_ERR_INVALID_ARGUMENT;
						goto out;
					}

					if (isAllZero(req->preload, VAULT_SINGLE_BLOCK_LEN)) {
LOGI("SEQ 3\n");
						ret = VK_SUCCESS;
						goto out;
					} else {
LOGI("SEQ 4\n");
						memcpy(&client_code, req->preload + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
						memcpy(&magic, req->preload + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
						old_client_code = 0xFAC2BB01;
						// VK3.2
						if (client_code == VTAB[req->vtab_index].client_code) {
LOGI("SEQ 5\n");
							// Copy new steady offset & Make recovery steady old vault
							ret = recovery_cass_legacy(target, req, req->preload, legacy_client_vault, 1);
							if (ret != VK_SUCCESS) goto out;

							// Set steady new
							rsp->req_steady.need_to_update = 1;
							rsp->req_steady.req_data_size = req->entire_vault_size;
							memcpy(rsp->req_steady.req_data, req->preload, req->entire_vault_size);
							// Set steady old
							rsp->req_steady.need_to_update_2nd = 1;
							rsp->req_steady.req_data_size_2nd = req->entire_vault_size;
							memcpy(rsp->req_steady.req_data_2nd, legacy_client_vault, req->entire_vault_size);				

							ret = VK_SUCCESS;
							LOGE("%s: migration_01 - success01\n", __func__);
							goto out;
						} else if (magic == old_client_code) {
LOGI("SEQ 6\n");
							// data migration -> steady new
							memcpy(client_stored_vault, req->preload, req->entire_vault_size);
							rsp->req_steady.need_to_update = 1;
							rsp->req_steady.req_data_size = req->entire_vault_size;
							memcpy(rsp->req_steady.req_data, req->preload, req->entire_vault_size);
						} else {
							// Error impossible
							LOGE("%s: Impossible normally\n", __func__);
							ret = VK_ERR_GENERAL;
							goto out;
						}
					}
				} else {
LOGI("SEQ 7\n");
					memcpy(&client_code, client_stored_vault + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
					memcpy(&magic, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
					old_client_code = 0xFAC2BB01;

					if (client_code == VTAB[req->vtab_index].client_code) {
LOGI("SEQ 8\n");
						// Copy new offset & Make recovery rpmb old vault & meta(170) -> steady new
						memcpy(&stored_sheltered_data_size, client_stored_vault + SHELTERED_VAULT_DATA_LEN_OFFSET, SHELTERED_VAULT_DATA_LEN_SIZE);
						sheltered_vault_size = VAULT_KEY_LEN + VAULT_KEY_LEN + SHELTERED_RESERVED + stored_sheltered_data_size;
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						read_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ));
						if (sheltered_vault_size != (read_cnt * RPMB_TRANSFER_MLT_BLK_READ * VAULT_SINGLE_BLOCK_LEN)) {
							read_cnt_extra = (uint32_t)(((float)(sheltered_vault_size - (read_cnt * RPMB_TRANSFER_MLT_BLK_READ * VAULT_SINGLE_BLOCK_LEN))
							                 /  VAULT_SINGLE_BLOCK_LEN) + 0.999999);
						} else {
							read_cnt_extra = 0;
						}
#else
						read_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ) + 0.999999);
#endif
						pTemp = client_stored_vault + VAULT_SINGLE_BLOCK_LEN;
						for (i = 0; i < read_cnt; i++) {
							ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
								                        cass_legacy_rpmb_index + 1 + (i * RPMB_TRANSFER_MLT_BLK_READ), pTemp, RPMB_TRANSFER_MLT_BLK_READ);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while reading vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (read_cnt_extra) {
							ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
													    cass_legacy_rpmb_index + 1 + (read_cnt * RPMB_TRANSFER_MLT_BLK_READ), pTemp, read_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while reading extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
								goto out;
							}
						}
#endif
						// write in new offset
						pTemp = (uint8_t*)client_stored_vault;
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						write_cnt = (uint32_t)((float)(sheltered_vault_size + VAULT_SINGLE_BLOCK_LEN) / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE));
						if (VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size != (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) {
							write_cnt_extra = (uint32_t)(((float)(VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size - (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) /  VAULT_SINGLE_BLOCK_LEN) + 0.999999);
						} else {
							write_cnt_extra = 0;
						}
#else
						write_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE) + 0.999999) + 1;
#endif
						// mirror
						for (i = 0; i < write_cnt; i++) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
								                         VTAB[req->vtab_index].start_index_rpmb_backup + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (write_cnt_extra) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
									                     VTAB[req->vtab_index].start_index_rpmb_backup + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing extra mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
						}
#endif
						// original
						pTemp = (uint8_t*)client_stored_vault;
						for (i = 0; i < write_cnt; i++) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
								                         VTAB[req->vtab_index].start_index_rpmb + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (write_cnt_extra) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
									                     VTAB[req->vtab_index].start_index_rpmb + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
						}
#endif
						ret = recovery_cass_legacy(target, req, client_stored_vault, legacy_client_vault, 2);
						if (ret != VK_SUCCESS) goto out;

						// write in legacy vault
						pTemp = (uint8_t*)legacy_client_vault;
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						write_cnt = VTAB[req->vtab_index].num_blocks / RPMB_TRANSFER_MLT_BLK_WRITE;
						write_cnt_extra = VTAB[req->vtab_index].num_blocks - (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE);
#else
						write_cnt = VTAB[req->vtab_index].num_blocks;
#endif
						// mirror
						for (i = 0; i < write_cnt; i++) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition, 
								                         cass_legacy_rpmb_index_backup + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (write_cnt_extra) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition, 
								                         cass_legacy_rpmb_index_backup + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing extra mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
						}
#endif
						// original
						pTemp = (uint8_t*)legacy_client_vault;
						for (i = 0; i < write_cnt; i++) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
								                         cass_legacy_rpmb_index + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (write_cnt_extra) {
							ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
								                         cass_legacy_rpmb_index + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while writing extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
								goto out;
							}
						}
#endif
						// Recovery meta vault for legacy
						memcpy(meta_vault, client_stored_vault + VAULT_META_OFFSET, VAULT_META_LEN);
						ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition, 170, meta_vault, VAULT_RPMB_BLOCK_UNIT);
						if (ret != VK_SUCCESS) {
							LOGE("%s: Something went wrong while writing vault(%d)\n", __func__, ret);
							goto out;
						}

						memset(legacy_client_vault, 0, MAX_VAULT_LEN);
						ret = recovery_cass_legacy(target, req, client_stored_vault, legacy_client_vault, 1);
						if (ret != VK_SUCCESS) goto out;

						rsp->req_steady.need_to_update = 1;
						rsp->req_steady.req_data_size = VAULT_SINGLE_BLOCK_LEN;
						memcpy(rsp->req_steady.req_data, client_stored_vault, VAULT_SINGLE_BLOCK_LEN);

						rsp->req_steady.need_to_update_2nd = 1;
						rsp->req_steady.req_data_size_2nd = MAX_VAULT_LEN;
						memcpy(rsp->req_steady.req_data_2nd, legacy_client_vault, MAX_VAULT_LEN);

						ret = VK_SUCCESS;
						LOGE("%s: migration_01 - success02\n", __func__);
						goto out;
					} else if (magic == old_client_code) {
LOGI("SEQ 9\n");
						// Read old offset - VK 3.1
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						read_cnt = (uint32_t)((VTAB[req->vtab_index].num_blocks - 1) / RPMB_TRANSFER_MLT_BLK_READ);
						read_cnt_extra = VTAB[req->vtab_index].num_blocks - 1 - (read_cnt * RPMB_TRANSFER_MLT_BLK_READ);
#else
						read_cnt = VTAB[req->vtab_index].num_blocks - 1;
#endif
						pTemp = client_stored_vault + VAULT_SINGLE_BLOCK_LEN;
						for (i = 0; i < read_cnt; i++) {
							ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
								                        cass_legacy_rpmb_index + 1 + (i * RPMB_TRANSFER_MLT_BLK_READ), pTemp, RPMB_TRANSFER_MLT_BLK_READ);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while reading vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
								goto out;
							}
							pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ;
						}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
						if (read_cnt_extra) {
							ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
													    cass_legacy_rpmb_index + 1 + (read_cnt * RPMB_TRANSFER_MLT_BLK_READ), pTemp, read_cnt_extra);
							if (ret != VK_SUCCESS) {
								LOGE("%s: Something went wrong while reading extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
								goto out;
							}
						}
#endif
						cass_write_vault_level = 2;
					} else {
						// Error impossible
						LOGE("%s: Impossible normally\n", __func__);
						ret = VK_ERR_GENERAL;
						goto out;
					}
				}
			} else {
LOGI("SEQ 10\n");
				memcpy(&client_code, client_stored_vault + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
				if (client_code == VTAB[req->vtab_index].client_code) {
					// Read legacy vault
					ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
							                    cass_legacy_rpmb_index, client_stored_vault, VAULT_RPMB_BLOCK_UNIT);
					if (ret != VK_SUCCESS) {
						LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
						goto out;
					}

					if (!isAllZero(client_stored_vault, VAULT_RPMB_BLOCK_UNIT)) {
						// Check version
						memcpy(&client_code, client_stored_vault + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
						if (client_code == VTAB[req->vtab_index].client_code) {
LOGI("SEQ 10-1\n");
							// Read old offset - VK 3.2
							memcpy(&stored_sheltered_data_size, client_stored_vault + SHELTERED_VAULT_DATA_LEN_OFFSET, SHELTERED_VAULT_DATA_LEN_SIZE);
							sheltered_vault_size = VAULT_KEY_LEN + VAULT_KEY_LEN + SHELTERED_RESERVED + stored_sheltered_data_size;

							if (stored_sheltered_data_size > MAX_SHELTERED_DATA_LEN) {
								LOGE("%s: Invalid stored sheltered data size(%d)\n", __func__, stored_sheltered_data_size);
								ret = VK_ERR_INVALID_ARGUMENT;
								goto out;
							}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							read_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ));
							if (sheltered_vault_size != (read_cnt * RPMB_TRANSFER_MLT_BLK_READ * VAULT_SINGLE_BLOCK_LEN)) {
								read_cnt_extra = (uint32_t)(((float)(sheltered_vault_size - (read_cnt * RPMB_TRANSFER_MLT_BLK_READ * VAULT_SINGLE_BLOCK_LEN)) /  VAULT_SINGLE_BLOCK_LEN) + 0.999999);
							} else {
								read_cnt_extra = 0;
							}
#else
							read_cnt = (int)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ) + 0.999999);
#endif
							pTemp = client_stored_vault + VAULT_SINGLE_BLOCK_LEN;
							for (i = 0; i < read_cnt; i++) {
								ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
										                    cass_legacy_rpmb_index + 1 + (i * RPMB_TRANSFER_MLT_BLK_READ), pTemp, RPMB_TRANSFER_MLT_BLK_READ);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while reading vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
									goto out;
								}
								pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ;
							}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							if (read_cnt_extra) {
								ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
														    cass_legacy_rpmb_index + 1 + (read_cnt * RPMB_TRANSFER_MLT_BLK_READ), pTemp, read_cnt_extra);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while reading extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
									goto out;
								}
							}
#endif
							// Write vault
							memcpy(&stored_sheltered_data_size, client_stored_vault + SHELTERED_VAULT_DATA_LEN_OFFSET, SHELTERED_VAULT_DATA_LEN_SIZE);
							sheltered_vault_size = VAULT_KEY_LEN + VAULT_KEY_LEN + SHELTERED_RESERVED + stored_sheltered_data_size;
							pTemp = (uint8_t*)client_stored_vault;
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							write_cnt = (uint32_t)((float)(sheltered_vault_size + VAULT_SINGLE_BLOCK_LEN) / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE));
							if (VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size != (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) {
								write_cnt_extra = (uint32_t)(((float)(VAULT_SINGLE_BLOCK_LEN + sheltered_vault_size - (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE * VAULT_SINGLE_BLOCK_LEN)) /  VAULT_SINGLE_BLOCK_LEN) + 0.999999);
							} else {
								write_cnt_extra = 0;
							}
#else
							write_cnt = (uint32_t)((float)sheltered_vault_size / (VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE) + 0.999999) + 1;
#endif
							for (i = 0; i < write_cnt; i++) {
								ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
										                     VTAB[req->vtab_index].start_index_rpmb_backup + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while writing mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
									goto out;
								}
								pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
							}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							if (write_cnt_extra) {
								ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
											                 VTAB[req->vtab_index].start_index_rpmb_backup + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while writing extra mirror vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
									goto out;
								}
							}
#endif
							pTemp = (uint8_t*)client_stored_vault;
							for (i = 0; i < write_cnt; i++) {
								ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
										                     VTAB[req->vtab_index].start_index_rpmb + (i * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, RPMB_TRANSFER_MLT_BLK_WRITE);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while writing vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
									goto out;
								}
								pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_WRITE;
							}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							if (write_cnt_extra) {
								ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition,
										                     VTAB[req->vtab_index].start_index_rpmb + (write_cnt * RPMB_TRANSFER_MLT_BLK_WRITE), pTemp, write_cnt_extra);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while writing extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_WRITE);
									goto out;
								}
							}
#endif
							// Write steady new
							rsp->req_steady.need_to_update = 1;
							rsp->req_steady.req_data_size = sheltered_vault_size + VAULT_SINGLE_BLOCK_LEN;
							memcpy(rsp->req_steady.req_data, client_stored_vault, rsp->req_steady.req_data_size);

							ret = VK_SUCCESS;
							LOGE("%s: migration_01 - success03\n", __func__);
							goto out;
						} else {
LOGI("SEQ 10-2\n");
							// Read old offset - VK 3.1
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							read_cnt = (uint32_t)((VTAB[req->vtab_index].num_blocks - 1) / RPMB_TRANSFER_MLT_BLK_READ);
							read_cnt_extra = VTAB[req->vtab_index].num_blocks - 1 - (read_cnt * RPMB_TRANSFER_MLT_BLK_READ);
#else
							read_cnt = VTAB[req->vtab_index].num_blocks - 1;
#endif
							pTemp = client_stored_vault + VAULT_SINGLE_BLOCK_LEN;
							for (i = 0; i < read_cnt; i++) {
								ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
										                    cass_legacy_rpmb_index + 1 + (i * RPMB_TRANSFER_MLT_BLK_READ), pTemp, RPMB_TRANSFER_MLT_BLK_READ);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while reading vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
									goto out;
								}
								pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ;
							}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
							if (read_cnt_extra) {
								ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
															cass_legacy_rpmb_index + 1 + (read_cnt * RPMB_TRANSFER_MLT_BLK_READ), pTemp, read_cnt_extra);
								if (ret != VK_SUCCESS) {
									LOGE("%s: Something went wrong while reading extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
									goto out;
								}
							}
#endif
							// Change to new vault
							cass_write_vault_level = 2;
						}
					} else {
						ret = VK_SUCCESS;
						LOGE("%s: migration_01 - success03\n", __func__);
						goto out;
					}
				} else {
					// Error impossible
					LOGE("%s: Impossible normally\n", __func__);
					ret = VK_ERR_GENERAL;
					goto out;
				}
			}
		} else {
			if (req->preload == NULL || req->preload_size == 0 || req->preload_size > req->entire_vault_size) {
				LOGE("%s: Invalid argument (preload)\n", __func__);
				ret = VK_ERR_INVALID_ARGUMENT;
				goto out;
			}

			if (isAllZero(req->preload, VAULT_SINGLE_BLOCK_LEN)) {
				ret = VK_SUCCESS;
				goto out;
			} else {
LOGI("SEQ 11\n");
				memcpy(&client_code, req->preload + CLIENT_CODE_OFFSET, CLIENT_CODE_LEN);
				memcpy(&magic, req->preload + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
				old_client_code = 0xFAC2BB01;

				// VK3.2
				if (client_code == VTAB[req->vtab_index].client_code) {
LOGI("SEQ 12\n");
					// Copy new steady offset & Make recovery steady old vault -> steady old, new
					ret = recovery_cass_legacy(target, req, req->preload, legacy_client_vault, 1);
					if (ret != VK_SUCCESS) goto out;

					rsp->req_steady.need_to_update = 1;
					rsp->req_steady.req_data_size = req->entire_vault_size;
					memcpy(rsp->req_steady.req_data, req->preload, req->entire_vault_size);

					rsp->req_steady.need_to_update_2nd = 1;
					rsp->req_steady.req_data_size_2nd = req->entire_vault_size;
					memcpy(rsp->req_steady.req_data_2nd, legacy_client_vault, req->entire_vault_size);

					ret = VK_SUCCESS;
					goto out;
				} else if (magic  == old_client_code) {
LOGI("SEQ 13\n");
					memcpy(client_stored_vault, req->preload, req->entire_vault_size);
					rsp->req_steady.need_to_update = 1;
					// data migration -> steady new
				} else {
					// Error impossible
					LOGE("%s: Impossible normally\n", __func__);
					ret = VK_ERR_GENERAL;
					goto out;
				}
			}
		}
	} else {
		// 1. Read client vault & Check if migration_01 done
		if (req->vault_level == VAULT_LEVEL1) {
			if (req->preload_size == 0 || req->preload_size > req->entire_vault_size) {
				LOGE("%s: Invalid preload size(%d)\n", __func__, req->preload_size);
				ret = VK_ERR_INVALID_ARGUMENT;
				goto out;
			}

			memcpy(client_stored_vault, req->preload, req->preload_size);

			if (isAllZero(client_stored_vault, req->preload_size)) {
				LOGE("%s: migration_01 - success04\n", __func__);
				ret = VK_SUCCESS;
				goto out;
			} else {
				// Check client_code & magic in unsheltered vault
				memcpy(&client_code, client_stored_vault + 32 + 4, sizeof(uint32_t));
				memcpy(&magic, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
				old_client_code = req->client_code - 0x01;

				if ((client_code == req->client_code) && (magic != old_client_code)) {
					ret = VK_SUCCESS;
					LOGE("%s: migration_01 - success05\n", __func__);
					goto out;
				}
			}
		} else if (req->vault_level == VAULT_LEVEL2) {
			write_vault_level = 2;

			if (g_device_info.rpmb_key_provisioning != 'T') {
				ret = VK_SUCCESS;
				LOGE("%s: migration_01 - success06\n", __func__);
				goto out;
			}
			// In case of KG
			if (!strncmp(VTAB[req->vtab_index].vault_name, VAULT_NAME_KG, sizeof(VAULT_NAME_KG))) {
				if (req->preload_size == 0) {
					LOGE("%s: migration_01 - success07\n", __func__);
					ret = VK_SUCCESS;
					goto out;
				}

				if (req->preload_size != req->entire_vault_size) {
					LOGE("%s: Invalid preload size(%d)\n", __func__, req->preload_size);
					ret = VK_ERR_INVALID_ARGUMENT;
					goto out;
				}

				rpmb_start_index = 3;

				// check client_code & magic in unsheltered_vault in old offset
				ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
					                        rpmb_start_index, client_stored_vault, VAULT_RPMB_BLOCK_UNIT);
				if (ret != VK_SUCCESS) {
					LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
					goto out;
				}

				if (isAllZero(client_stored_vault, VAULT_SINGLE_BLOCK_LEN)) {
					LOGE("%s: migration_01 - success08\n", __func__);
					ret = VK_SUCCESS;
					goto out;
				}

				memcpy(&client_code, client_stored_vault + 32 + 4, sizeof(uint32_t));
				memcpy(&magic, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
				old_client_code = req->client_code - 0x01;

				if ((client_code == req->client_code) && (magic != old_client_code)) {
					LOGE("%s: migration_01 - success09\n", __func__);
					ret = VK_SUCCESS;
					goto out;
				}

				memcpy(client_stored_vault + VAULT_SINGLE_BLOCK_LEN, req->preload + VAULT_SINGLE_BLOCK_LEN, req->entire_vault_size - VAULT_SINGLE_BLOCK_LEN);

			// In case others
			} else {
				// check client_code & magic in unsheltered_vault
				ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
					                        VTAB[req->vtab_index].start_index_rpmb, client_stored_vault, VAULT_RPMB_BLOCK_UNIT);
				if (ret != VK_SUCCESS) {
					LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
					goto out;
				}

				if (!isAllZero(client_stored_vault, VAULT_SINGLE_BLOCK_LEN)) {
					memcpy(&client_code, client_stored_vault + 32 + 4, sizeof(uint32_t));
					memcpy(&magic, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4), sizeof(uint32_t));
					old_client_code = req->client_code - 0x01;

					if ((client_code == req->client_code) && (magic != old_client_code)) {
						LOGE("%s: migration_01 - success10\n", __func__);
						ret = VK_SUCCESS;
						goto out;
					}
				} else {
					// check client_code & magic in sheltered_vault
					ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
						                        VTAB[req->vtab_index].start_index_rpmb + 1, client_stored_vault + VAULT_SINGLE_BLOCK_LEN, VAULT_RPMB_BLOCK_UNIT);
					if (ret != VK_SUCCESS) {
						LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
						goto out;
					}

					if (!isAllZero(client_stored_vault + VAULT_SINGLE_BLOCK_LEN, VAULT_SINGLE_BLOCK_LEN)) {
						memcpy(&magic, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN + 32), sizeof(uint32_t));
						old_client_code = req->client_code - 0x01;

						if (magic != old_client_code) {
							LOGE("%s: migration_01 - success11\n", __func__);
							ret = VK_SUCCESS;
							goto out;
						}
					} else {
						LOGE("%s: migration_01 - success12\n", __func__);
						ret = VK_SUCCESS;
						goto out;
					}
				}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
				read_cnt = (uint32_t)((VTAB[req->vtab_index].num_blocks - 1) / RPMB_TRANSFER_MLT_BLK_READ);
				read_cnt_extra = VTAB[req->vtab_index].num_blocks - 1 - (read_cnt * RPMB_TRANSFER_MLT_BLK_READ);
#else
				read_cnt = VTAB[req->vtab_index].num_blocks - 1;
#endif
				pTemp = client_stored_vault + VAULT_SINGLE_BLOCK_LEN;
				for (i = 0; i < read_cnt; i++) {
					ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
						                        VTAB[req->vtab_index].start_index_rpmb + 1 + (i * RPMB_TRANSFER_MLT_BLK_READ), pTemp, RPMB_TRANSFER_MLT_BLK_READ);
					if (ret != VK_SUCCESS) {
						LOGE("%s: Something went wrong while reading vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
						goto out;
					}
					pTemp += VAULT_SINGLE_BLOCK_LEN * RPMB_TRANSFER_MLT_BLK_READ;
				}
#ifdef VK_RPMB_TRANSFER_MLT_BLK
				if (read_cnt_extra) {
					ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
												VTAB[req->vtab_index].start_index_rpmb + 1 + (read_cnt * RPMB_TRANSFER_MLT_BLK_READ), pTemp, read_cnt_extra);
					if (ret != VK_SUCCESS) {
						LOGE("%s: Something went wrong while reading extra vault(%d/%d)\n", __func__, ret, RPMB_TRANSFER_MLT_BLK_READ);
						goto out;
					}
				}
#endif

				// Read meta vault
				meta_vault_index = VTAB[req->vtab_index].start_index_rpmb_backup + VTAB[req->vtab_index].num_blocks;
				ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition,
					                        meta_vault_index, meta_vault, VAULT_RPMB_BLOCK_UNIT);
				if (ret != VK_SUCCESS) {
					LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
					goto out;
				}
			}
		} else {
			LOGE("%s: Invalid vault_level type(%d)\n", __func__, req->vault_level);
			ret = VK_ERR_INVALID_ARGUMENT;
			goto out;	
		}
	}

	// with random IV
	if ((write_vault_level == 2 && 
		strncmp(VTAB[req->vtab_index].vault_name, VAULT_NAME_KG, sizeof(VAULT_NAME_KG))) ||
		cass_write_vault_level == 2) {

		unsheltered_enc_offset = 32 + 16;
		unsheltered_enc_size = 92 + 32 + 32;

		memcpy(stored_iv, client_stored_vault + 32, 16);
		if (isAllZero(stored_iv, 16)) {
			LOGE("%s: Failed to get iv\n", __func__);
			ret = VK_ERR_GENERAL;
			goto out;
		}

		if (cass_write_vault_level == 2) {
			ret = target->platform.read(VTAB[req->vtab_index].rpmb_partition, 170, meta_vault, VAULT_RPMB_BLOCK_UNIT);
			if (ret != VK_SUCCESS) {
				LOGE("%s: Something went wrong while reading vault(%d)\n", __func__, ret);
				goto out;
			}

			meta_vault[META_CP_DATA_MIGRATION] = META_FUSE_BLOWN;
			meta_vault[META_CP_DATA_KPF] = META_FUSE_BLOWN;
		}
	// without random IV
	} else {
		unsheltered_enc_offset = 16;
		unsheltered_enc_size = 124 + 32 + 32;

		ret = VK_GET_SECURE_ITEM(VK_SECURE_ITEM_LEGACY_FIXED_IV, stored_iv, AES_IV_LEN);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Failed VK_GET_SECURE_ITEM(%d/%d)\n", __func__, VK_SECURE_ITEM_LEGACY_FIXED_IV, ret);
			goto out;
		}
	}

	sheltered_enc_offset = VAULT_SINGLE_BLOCK_LEN + 32 + 4 + 16;
	sheltered_enc_size = (VTAB[req->vtab_index].num_blocks * VAULT_SINGLE_BLOCK_LEN) - VAULT_SINGLE_BLOCK_LEN - 32 - 4 - 16;

	ret = target->platform.memory_alloc(&buf, sheltered_enc_size);
	if (ret != VK_SUCCESS || buf == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		goto out;
	}

	// 2. unwrap unsheltered vault
	if (!isAllZero(client_stored_vault, VAULT_SINGLE_BLOCK_LEN)) {
		memcpy(stored_gcm_tag, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4 - 16), 16);

		ret = vk_crypto_aes_256_gcm_decrypt(client_stored_vault + unsheltered_enc_offset, unsheltered_enc_size, buf, &buf_len,
											stored_gcm_tag, sizeof(stored_gcm_tag), NULL, stored_iv);

		if (ret != VK_SUCCESS || buf_len != unsheltered_enc_size) {
			LOGE("%s: Failed to decrypt with aes gcm(%d/%u/%u)\n", __func__, ret, unsheltered_enc_size, buf_len);
			goto out;
		}

		memcpy(client_stored_vault + unsheltered_enc_offset, buf, buf_len);
		memset(buf, 0, buf_len);
	}

	// 3. unwrap sheltered vault
	if (!isAllZero(client_stored_vault + VAULT_SINGLE_BLOCK_LEN, VAULT_SINGLE_BLOCK_LEN)) {
		memcpy(stored_gcm_tag, client_stored_vault + VAULT_SINGLE_BLOCK_LEN + 32 + 4, 16);

		ret = vk_crypto_aes_256_gcm_decrypt(client_stored_vault + sheltered_enc_offset, sheltered_enc_size, buf, &buf_len,
											stored_gcm_tag, sizeof(stored_gcm_tag), NULL, stored_iv);

		if (ret != VK_SUCCESS || buf_len != sheltered_enc_size) {
			LOGE("%s: Failed to decrypt with aes gcm(%d/%u/%u)\n", __func__, ret, sheltered_enc_size, buf_len);
			goto out;
		}

		memcpy(&stored_sheltered_data_size, buf, sizeof(uint32_t));

		memcpy(client_stored_vault + sheltered_enc_offset, buf, buf_len);
		memset(buf, 0, buf_len);	
	}

	memcpy(new_unsheltered_data, client_stored_vault, MAX_UNSHELTERED_DATA_LEN);
	new_client_code = req->client_code;
	memcpy(new_iv, req->random_iv, AES_IV_LEN);
	memcpy(new_meta, meta_vault, VAULT_META_LEN);
	memcpy(new_key, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4 - 16 - 32 - 32), VAULT_KEY_LEN);
	memcpy(new_key2, client_stored_vault + (VAULT_SINGLE_BLOCK_LEN - 32 - 4 - 16 - 32), VAULT_KEY_LEN);

	// CASS. default sheltered data size : 160
	if (!strncmp(VTAB[req->vtab_index].vault_name, VAULT_NAME_CASS, sizeof(VAULT_NAME_CASS)) && (stored_sheltered_data_size < 160)) {
		stored_sheltered_data_size = 160;
	}

	if (stored_sheltered_data_size > MAX_SHELTERED_DATA_LEN) {
		LOGE("%s: Invalid stored sheltered data size(%d)\n", __func__, stored_sheltered_data_size);
		ret = VK_ERR_INVALID_ARGUMENT;
		goto out;
	}

	new_sheltered_data_size = stored_sheltered_data_size;

	// 4. restruct
	ret = target->platform.memory_alloc(&new_client_vault, req->entire_vault_size);
	if (ret != VK_SUCCESS || new_client_vault == NULL) {
		LOGE("%s: Failed memory alloc(%d)\n", __func__, ret);
		goto out;
	}

	memcpy(new_client_vault->unsheltered.unsheltered_data, new_unsheltered_data, MAX_UNSHELTERED_DATA_LEN);
	new_client_vault->unsheltered.sheltered_data_size = new_sheltered_data_size;
	new_client_vault->unsheltered.client_code = new_client_code;
	memcpy(new_client_vault->unsheltered.iv, new_iv, AES_IV_LEN);
	memcpy(new_client_vault->unsheltered.meta, new_meta, VAULT_META_LEN);

	memcpy(new_client_vault->sheltered.key, new_key, VAULT_KEY_LEN);
	memcpy(new_client_vault->sheltered.privated, new_key2, VAULT_KEY_LEN);

	if (new_client_vault->unsheltered.sheltered_data_size > 0)
		memcpy(new_client_vault->sheltered.sheltered_data, client_stored_vault + sheltered_enc_offset + sizeof(uint32_t),
				new_client_vault->unsheltered.sheltered_data_size);
	
	// 5. write
	if (write_vault_level == 2 || cass_write_vault_level == 2)
		req->vault_level = VAULT_LEVEL2;

	ret = target->vault.write_entire_vault(target, req, rsp, new_client_vault);
	if (ret != VK_SUCCESS) {
		LOGE("%s: Failed to write vault(%d)\n", __func__, ret);
		goto out;
	}

	// KG
	if (write_vault_level == 2 && !strncmp(VTAB[req->vtab_index].vault_name, VAULT_NAME_KG, sizeof(VAULT_NAME_KG))) {
		ret = target->platform.write(VTAB[req->vtab_index].rpmb_partition, rpmb_start_index, new_client_vault, VAULT_RPMB_BLOCK_UNIT);
		if (ret != VK_SUCCESS) {
			LOGE("%s: Something went wrong while writing vault(%d)\n", __func__, ret);
			goto out;
		}
	}

out:
	memset(new_key, 0, VAULT_KEY_LEN);
	memset(new_key2, 0, VAULT_KEY_LEN);

	if (buf != NULL) {
		target->platform.memory_free(buf);
	}

	if (new_client_vault != NULL) {
		memset((uint8_t*)new_client_vault, 0, req->entire_vault_size);
		target->platform.memory_free(new_client_vault);
	}

	if (client_stored_vault != NULL) {
		memset((uint8_t*)client_stored_vault, 0, MAX_VAULT_LEN);
		target->platform.memory_free(client_stored_vault);
	}

	if (legacy_client_vault != NULL) {
		memset((uint8_t*)legacy_client_vault, 0, MAX_VAULT_LEN);
		target->platform.memory_free(legacy_client_vault);
	}

	LOGI("%s: migration_01 done\n", __func__);

	return ret;
}
