From: Dongsun Lee Date: Mon, 23 Dec 2024 05:51:12 +0000 (+0900) Subject: Add documentation for storing large or frequently updated data X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen;p=platform%2Fcore%2Fsecurity%2Fkey-manager.git Add documentation for storing large or frequently updated data Change-Id: Ieecbc630773260f895f84bad373ab3122fbbb6b0 --- diff --git a/doc/examples/data_store.cpp b/doc/examples/data_store.cpp new file mode 100644 index 00000000..db0013be --- /dev/null +++ b/doc/examples/data_store.cpp @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +#include +#include +#include + +#include + +//! [DATA_STORE example] +static int save_small_stable_data(const char *alias, ckmc_raw_buffer_s data) +{ + ckmc_policy_s policy; + + if (alias == NULL || data.data == NULL || data.size == 0) + return CKMC_ERROR_INVALID_PARAMETER; + + policy.password = NULL; + policy.extractable = true; + + return ckmc_save_data(alias, data, policy); +} + +static int get_small_stable_data(const char *alias, ckmc_raw_buffer_s **data_buffer) +{ + int ret = CKMC_ERROR_NONE; + ckmc_raw_buffer_s *output = NULL; + + if (alias == NULL || data_buffer == NULL) + return CKMC_ERROR_INVALID_PARAMETER; + + ret = ckmc_get_data(alias, NULL, &output); + if (CKMC_ERROR_NONE != ret) { + if (output) + ckmc_buffer_free(output); + return ret; + } + + *data_buffer = output; + return CKMC_ERROR_NONE; +} + + +const char *KEY_ALIAS = "MY_MODULE_KEY_NAME"; +const char *DATA_STORE_PATH = "MY_DATA_STORE_PATH/"; + +static int create_aes_key(const char *alias) +{ + ckmc_policy_s policy; + policy.password = NULL; + policy.extractable = false; + + return ckmc_create_key_aes(256, alias, policy); +} + +static int save_large_frequently_updated_data(const char *alias, ckmc_raw_buffer_s data) +{ + int ret = CKMC_ERROR_NONE; + ckmc_param_list_h params = NULL; + ckmc_raw_buffer_s* output = NULL; + ckmc_raw_buffer_s* iv = NULL; + unsigned char iv_binary[16] = {}; + int iv_size = sizeof(iv_binary); + int random = 0; + char *filename = NULL; + FILE* fp = NULL; + size_t write_len = 0; + + ret = ckmc_generate_new_params(CKMC_ALGO_AES_CBC, ¶ms); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + // set IV from random value + for (size_t i = 0; i < iv_size; i += sizeof(random)) { + random = rand(); + memcpy(iv_binary + i, &random, + sizeof(random) < iv_size - i ? + sizeof(random) : iv_size - i); + } + + ret = ckmc_buffer_new(iv_binary, iv_size, &iv); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + ret = ckmc_param_list_set_buffer(params, CKMC_PARAM_ED_IV, iv); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + // encrypt data + ret = ckmc_encrypt_data(params, KEY_ALIAS, "", data, &output); + if (ret == CKMC_ERROR_DB_ALIAS_UNKNOWN) { // in case of no key created before + ret = create_aes_key(KEY_ALIAS); + if (ret != CKMC_ERROR_NONE) + goto finish; + ret = ckmc_encrypt_data(params, KEY_ALIAS, "", data, &output); + } + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + // get file name + filename = (char *) calloc(1, strlen(DATA_STORE_PATH) + strlen(alias) + 1); + if (filename == NULL) { + ret = TIZEN_ERROR_OUT_OF_MEMORY; + goto finish; + } + strncpy(filename, DATA_STORE_PATH, strlen(DATA_STORE_PATH)); + strncpy(filename + strlen(DATA_STORE_PATH), alias, strlen(alias)); + + // open file to write + if ((fp = fopen(filename, "wb")) == NULL) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + // write data size to file + if ((write_len = fwrite(&output->size, sizeof(output->size), 1, fp)) != 1) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + // write iv size to file + if ((write_len = fwrite(&iv_size, sizeof(output->size), 1, fp)) != 1) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + // write data to file + if ((write_len = fwrite(output->data, sizeof(char), output->size, fp)) < output->size) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + // write iv to file + if ((write_len = fwrite(iv_binary, sizeof(char), sizeof(iv_binary), fp)) < sizeof(iv_binary)) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + +finish: + ckmc_param_list_free(params); + ckmc_buffer_free(output); + ckmc_buffer_free(iv); + if (fp) + fclose(fp); + if (filename) + free(filename); + + return ret; +} + +static int get_large_frequently_updated_data(const char *alias, ckmc_raw_buffer_s **data_buffer) +{ + int ret = CKMC_ERROR_NONE; + ckmc_param_list_h params = NULL; + ckmc_raw_buffer_s encrypted; + ckmc_raw_buffer_s iv; + ckmc_raw_buffer_s* decrypted = NULL; + unsigned char *encrypted_binary = NULL; + unsigned char *iv_binary = NULL; + size_t data_size = 0; + size_t iv_size = 0; + size_t read_len = 0; + char *filename = NULL; + FILE* fp = NULL; + + if (alias == NULL || data_buffer == NULL) + return CKMC_ERROR_INVALID_PARAMETER; + + ret = ckmc_generate_new_params(CKMC_ALGO_AES_CBC, ¶ms); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + // get file name + filename = (char *) calloc(1, strlen(DATA_STORE_PATH) + strlen(alias) + 1); + if (filename == NULL) { + ret = TIZEN_ERROR_OUT_OF_MEMORY; + goto finish; + } + strncpy(filename, DATA_STORE_PATH, strlen(DATA_STORE_PATH)); + strncpy(filename + strlen(DATA_STORE_PATH), alias, strlen(alias)); + + // open file to read + if ((fp = fopen(filename, "rb")) == NULL) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + + // read sizes for data and iv + read_len = fread(&data_size, sizeof(data_size), 1, fp); + if (read_len != 1) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + read_len = fread(&iv_size, sizeof(iv_size), 1, fp); + if (read_len != 1) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + + // get encrypted binary + encrypted_binary = (unsigned char *) malloc(data_size); + if (encrypted_binary == NULL) { + ret = TIZEN_ERROR_OUT_OF_MEMORY; + goto finish; + } + encrypted.data = encrypted_binary; + encrypted.size = data_size; + read_len = fread(encrypted_binary, sizeof(char), data_size, fp); + if (read_len != data_size) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + + // get iv binary + iv_binary = (unsigned char *) malloc(iv_size); + if (iv_binary == NULL) { + ret = TIZEN_ERROR_OUT_OF_MEMORY; + goto finish; + } + iv.data = iv_binary; + iv.size = iv_size; + read_len = fread(iv_binary, 1, iv_size, fp); + if (read_len != iv_size) { + ret = TIZEN_ERROR_IO_ERROR; + goto finish; + } + + ret = ckmc_param_list_set_buffer(params, CKMC_PARAM_ED_IV, &iv); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + // decrypt data + ret = ckmc_decrypt_data(params, KEY_ALIAS, "", encrypted, &decrypted); + if (ret != CKMC_ERROR_NONE) { + goto finish; + } + + *data_buffer = decrypted; + +finish: + ckmc_param_list_free(params); + if (fp) + fclose(fp); + if (filename) + free(filename); + if (iv_binary) + free(iv_binary); + if (encrypted_binary) + free(encrypted_binary); + if (ret != CKMC_ERROR_NONE) + ckmc_buffer_free(decrypted); + + return ret; +} + +//! [DATA_STORE example] + +bool compare_binary(ckmc_raw_buffer_s* buf1, ckmc_raw_buffer_s *buf2) +{ + if (buf1 == NULL || buf2 == NULL) + return false; + if (buf1->size != buf2->size) + return false; + for (size_t i = 0; i < buf1->size; i++) + if (buf1->data[i] != buf2->data[i]) + return false; + return true; +} + +void test_small_data() +{ + int ret = CKMC_ERROR_NONE; + const char* alias = "TEST_DATA"; + unsigned char binary[8] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x06, 0x07, 0x08} ; + ckmc_raw_buffer_s data; + data.data = binary; + data.size = sizeof(binary); + ckmc_raw_buffer_s *output = NULL; + + ret = save_small_stable_data(alias, data); + if (ret != CKMC_ERROR_NONE) + printf("test_small_data: save_small_stable_data failed. ret = %d\n", ret); + + ret = get_small_stable_data(alias, &output); + if (ret != CKMC_ERROR_NONE) + printf("test_small_data: get_small_stable_data failed. ret = %d\n", ret); + + if (!compare_binary(&data, output)) + printf("test_small_data : the output is not the same as the input.\n"); + else + printf("test_small_data : Success.\n"); + + if (output != NULL) + ckmc_buffer_free(output); +} + +void test_large_data() +{ + int ret = 0; + const char* alias = "TEST_DATA"; + unsigned char binary[128] = {0x01,} ; + ckmc_raw_buffer_s data; + data.data = binary; + data.size = sizeof(binary); + ckmc_raw_buffer_s *output = NULL; + + ret = save_large_frequently_updated_data(alias, data); + if (ret != CKMC_ERROR_NONE) + printf("test_large_data: save_large_frequently_updated_data failed. ret = %d\n", ret); + + ret = get_large_frequently_updated_data(alias, &output); + if (ret != CKMC_ERROR_NONE) + printf("test_large_data: get_large_frequently_updated_data failed. ret = %d\n", ret); + + + if (!compare_binary(&data, output)) + printf("test_large_data : the output is not the same as the input.\n"); + else + printf("test_large_data : Success.\n"); + + if (output != NULL) + ckmc_buffer_free(output); +} + + +int main() +{ + test_small_data(); + test_large_data(); + return 0; +} diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 0070dd0b..546a10f8 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -622,6 +622,14 @@ int ckmc_get_pkcs12(const char *alias, * @remarks %http://tizen.org/privilege/keymanager (public level privilege) is no longer required to * use this function since 3.0. * + * @remarks Although the Key Manager can store data securely on its repository, it is not designed + * to handle large amounts of data (more than 32 bytes) or frequently updated data. + * Therefore, we recommend creating an AES key for each client specifically + * to encrypt/decrypt larger or frequently updated data. Once you have generated the AES key, + * you can then encrypt your data using this key before storing it in a file system accessible + * by the client. This way, when the client requires access to the data, + * they can easily decrypt it using their respective AES key. + * * @param[in] alias The name of a data to be stored * @param[in] data The binary value to be stored * @param[in] policy Data storing policy @@ -636,11 +644,15 @@ int ckmc_get_pkcs12(const char *alias, * * @pre User is already logged in and the user key is already loaded into memory in plain text form. * + * @par Example + * @snippet data_store.cpp DATA_STORE example + * * @see ckmc_remove_alias() * @see ckmc_get_data() * @see ckmc_get_data_alias_list() * @see #ckmc_raw_buffer_s * @see #ckmc_policy_s + * */ int ckmc_save_data(const char *alias, ckmc_raw_buffer_s data,