From 93e2958cbd6089f12962d432fdb832bee32e2098 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 1 Apr 2015 11:45:48 +0200 Subject: [PATCH] Encryption/decryption API [Issue#] N/A [Feature] Encryption decryption support [Problem] N/A [Cause] N/A [Solution] API for encryption decryption [Verification] Succesfull compilation. Run tests ckm-tests --group=ALGO_PARAMS (all pass) ckm-tests --group=ENCRYPTION_DECRYPTION (all fail with CKMC_ERROR_UNKNOWN) Change-Id: I6cbb1fb56ad1d82f8d673ed27d22eade82e4e1d0 --- src/include/ckmc/ckmc-manager.h | 76 +++++++++++ src/include/ckmc/ckmc-type.h | 225 +++++++++++++++++++++++++++++++ src/manager/client-capi/ckmc-manager.cpp | 22 +++ src/manager/client-capi/ckmc-type.cpp | 155 ++++++++++++++++++--- 4 files changed, 461 insertions(+), 17 deletions(-) diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index ed4113d..7210026 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -1134,6 +1134,82 @@ int ckmc_deny_access(const char *alias, const char *accessor); */ int ckmc_remove_alias(const char *alias); +/** + * @brief Encrypts data using selected key and algorithm + * + * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/keymanager + * + * @remarks Key identified by @a key_alias should exist + * + * @param[in] params Algorithm parameters + * @param[in] key_alias Alias of the key to be used for encryption + * @param[in] password The password used in decrypting a key value. If password of policy + * is provided in ckmc_save_key(), the same password should be provided + * @param[in] decrypted Data to be encrypted + * @param[out] ppencrypted Encrypted data (some algorithms may return additional information + * embedded in encrypted data. AES GCM is an example). The caller is + * responsible for freeing ppencrypted with ckmc_buffer_free(). + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * @retval #CKMC_ERROR_DB_LOCKED A user key is not loaded in memory (a user is not logged + * in) + * @retval #CKMC_ERROR_DB_ERROR Failed due to the error with unknown reason + * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN Key with given alias does not exist + * @retval #CKMC_ERROR_PERMISSION_DENIED Failed to access key manager + * @retval #CKMC_ERROR_AUTHENTICATION_FAILED + * Key decryption failed because password is incorrect. + * + * @pre User is already logged in and the user key is already loaded into memory in plain text form. + */ +int ckmc_encrypt_data(const ckmc_param_list_s *params, + const char *key_alias, + const char *password, + const ckmc_raw_buffer_s decrypted, + ckmc_raw_buffer_s **ppencrypted); + +/** + * @brief Decrypts data using selected key and algorithm + * + * @since_tizen 3.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/keymanager + * + * @remarks Key identified by @a key_alias should exist + * + * @param[in] params Algorithm parameters + * @param[in] key_alias Alias of the key to be used for encryption + * @param[in] password The password used in decrypting a key value. If password of policy + * is provided in ckmc_save_key(), the same password should be provided + * @param[in] encrypted Data to be decrypted (some algorithms may require additional + * information embedded in encrypted data. AES GCM is an example). + * @param[out] ppdecrypted Decrypted data. The caller is responsible for freeing ppdecrypted + * with ckmc_buffer_free(). + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * @retval #CKMC_ERROR_DB_LOCKED A user key is not loaded in memory (a user is not logged + * in) + * @retval #CKMC_ERROR_DB_ERROR Failed due to the error with unknown reason + * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN Key with given alias does not exist + * @retval #CKMC_ERROR_PERMISSION_DENIED Failed to access key manager + * @retval #CKMC_ERROR_AUTHENTICATION_FAILED + * Key decryption failed because password is incorrect. + * + * @pre User is already logged in and the user key is already loaded into memory in plain text form. + */ +int ckmc_decrypt_data(const ckmc_param_list_s *params, + const char *key_alias, + const char *password, + const ckmc_raw_buffer_s encrypted, + ckmc_raw_buffer_s **ppdecrypted); + #ifdef __cplusplus } #endif diff --git a/src/include/ckmc/ckmc-type.h b/src/include/ckmc/ckmc-type.h index fbb30ab..9a9669f 100644 --- a/src/include/ckmc/ckmc-type.h +++ b/src/include/ckmc/ckmc-type.h @@ -23,6 +23,7 @@ #define __TIZEN_CORE_CKMC_TYPE_H #include +#include #include #define KEY_MANAGER_CAPI __attribute__((visibility("default"))) @@ -218,6 +219,99 @@ typedef struct __ckmc_pkcs12 { ckmc_cert_list_s *ca_chain; /**< chain certificates list, may be null */ } ckmc_pkcs12_s; +/** + * @brief Enumeration for crypto algorithm parameters. + * @since_tizen 3.0 + */ +typedef enum __ckmc_param_name { + CKMC_PARAM_ALGO_TYPE = 1, + + // encryption & decryption + CKMC_PARAM_ED_IV = 101, /**< 16B buffer (up to 2^64-1 bytes long in case of AES GCM) */ + CKMC_PARAM_ED_CTR_LEN, /**< integer */ + CKMC_PARAM_ED_AAD, /**< buffer */ + CKMC_PARAM_ED_TAG_LEN, /**< integer */ + CKMC_PARAM_ED_LABEL, /**< buffer */ + + // key generation + CKMC_PARAM_GEN_KEY_LEN = 201, /**< integer */ + CKMC_PARAM_GEN_EC, /**< integer - elliptic curve (ckmc_ec_type_e) */ + + // sign & verify + CKMC_PARAM_SV_HASH_ALGO = 301, /**< integer - hash algorithm (ckmc_hash_algo_e) */ + CKMC_PARAM_SV_RSA_PADDING, /**< integer - RSA padding (ckmc_rsa_padding_algo_e) */ +}ckmc_param_name_e; + +/** + * @brief Structure for algorithm parameter list. + * @since_tizen 3.0 + */ +struct ckmc_param_list_s; + +/** + * @brief Enumeration for crypto algorithm types. + * @since_tizen 3.0 + */ +typedef enum __ckmc_algo_type { + CKMC_ALGO_AES_CTR = 1, /**< AES-CTR algorithm + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_ED_IV + - CKMC_PARAM_ED_CTR_LEN (128 only) */ + + CKMC_ALGO_AES_CBC, /**< AES-CBC algorithm + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_ED_IV */ + + CKMC_ALGO_AES_GCM, /**< AES-GCM algorithm + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_ED_IV + - CKMC_PARAM_ED_TAG_LEN + - CKMC_PARAM_ED_AAD */ + + CKMC_ALGO_AES_CFB, /**< AES-CFB algorithm + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_ED_IV */ + + CKMC_ALGO_RSA_OAEP, /**< RSA-OAEP algorithm + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_ED_LABEL */ + + CKMC_ALGO_RSA_SV, /**< RSA algorithm used for signing/verification + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_SV_HASH_ALGO + - CKMC_PARAM_SV_RSA_PADDING */ + + CKMC_ALGO_DSA_SV, /**< DSA algorithm used for signing/verification + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_SV_HASH_ALGO */ + + CKMC_ALGO_ECDSA_SV, /**< ECDA algorithm used for signing/verification + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_SV_HASH_ALGO */ + + CKMC_ALGO_RSA_GEN, /**< RSA algorithm used for key generation + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_GEN_KEY_LEN */ + + CKMC_ALGO_DSA_GEN, /**< DSA algorithm used for key generation + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_GEN_KEY_LEN */ + + CKMC_ALGO_ECDSA_GEN, /**< ECDA algorithm used for key generation + Supported parameters: + - CKMC_PARAM_ALGO_TYPE, + - CKMC_PARAM_GEN_EC */ +} ckmc_algo_type_e; /** * @internal @@ -643,6 +737,137 @@ void ckmc_cert_list_free(ckmc_cert_list_s *first); void ckmc_cert_list_all_free(ckmc_cert_list_s *first); /** + * @brief Creates new parameter list + * + * @since_tizen 3.0 + * + * @remarks Caller is responsible for freeing it with ckmc_param_list_free + * + * @param[in] ppparam_list Double pointer to the list variable to which the newly created list will + * be assigned. Last element of the list has param = NULL; + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * + * @see ckmc_param_list_add_integer + * @see ckmc_param_list_add_buffer + * @see ckmc_param_list_free + * @see ckmc_generate_params + * @see #ckmc_param_list_s + * @see #ckmc_param_name_e + */ +int ckmc_param_list_new(ckmc_param_list_s **ppparams); + +/** + * @brief Adds integer parameter to the list + * + * @since_tizen 3.0 + * + * @remarks Caller is responsible for ckmc_param_list_s creation. + * @remarks Last element of the list has param = NULL; + * + * @param[in] previous Any element of the param list. + * @param[in] name Name of parameter to add. Each parameter name has an associated value type: + * integer or buffer. Passing a buffer parameter name will result in an error + * @param[in] value Value of the parameter in form of a integer. + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * + * @see ckmc_param_list_new + * @see ckmc_param_list_add_buffer + * @see ckmc_param_list_free + * @see ckmc_generate_params + * @see #ckmc_param_list_s + * @see #ckmc_param_name_e + */ +int ckmc_param_list_add_integer(ckmc_param_list_s *params, + ckmc_param_name_e name, + uint64_t value); + +/** + * @brief Adds buffer parameter to the list + * + * @since_tizen 3.0 + * + * @remarks Caller is responsible for ckmc_param_list_s creation. + * @remarks Last element of the list has param = NULL; + * + * @param[in] previous Any element of the param list. + * @param[in] name Name of parameter to add. Each parameter name has an associated value type: + * integer or buffer. Passing an integer parameter name will result in an error + * @param[in] buffer Value of the parameter in form of a buffer. Caller is responsible for + * creating and freeing the buffer. + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * + * @see ckmc_param_list_new + * @see ckmc_param_list_add_integer + * @see ckmc_param_list_free + * @see ckmc_generate_params + * @see #ckmc_param_list_s + * @see #ckmc_param_name_e + */ +int ckmc_param_list_add_buffer(ckmc_param_list_s *params, + ckmc_param_name_e name, + const ckmc_raw_buffer_s *buffer); + +/** + * @brief Frees previously allocated list of algorithm params + * + * @since_tizen 3.0 + * + * @param[in] first First element of the list to be freed. + * + * @see ckmc_param_list_new + * @see ckmc_param_list_add_integer + * @see ckmc_param_list_add_buffer + * @see ckmc_generate_params + * @see #ckmc_param_list_s + * @see #ckmc_param_name_e + */ +void ckmc_param_list_free(ckmc_param_list_s *params); + +/** + * @brief Generates algorithm parameters for a given algorithm type and adds them to the list. + * + * @since_tizen 3.0 + * + * @remarks Caller is responsible for ckmc_param_list_s creation and destruction. + * @remarks Algorithm parameters used for encryption could be then used for decryption but this + * function should not be used for generating decryption parameters only. + * @remarks Algorithm parameters are set to default values. Optional fields are left empty. + * Initialization vectors are randomly generated. Param list passed as ckmc_param_list_s + * will be extended with new params. Caller is responsible for freeing the list + * with ckmc_param_list_free. + * @remarks If the function returns error provided param list may contain some of default parameters + * + * @param[in] type Type of the algorithm + * @param[out] params List of params to be filled. List should be empty. Otherwise an error will + * be returned. + * + * @return @c 0 on success, otherwise a negative error value + * + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * + * @see ckmc_param_list_new + * @see ckmc_param_list_add_integer + * @see ckmc_param_list_add_buffer + * @see ckmc_param_list_free + * @see #ckmc_param_list_s + * @see #ckmc_param_name_e + */ +int ckmc_generate_params(ckmc_algo_type_e type, ckmc_param_list_s *params); + +/** * @} */ diff --git a/src/manager/client-capi/ckmc-manager.cpp b/src/manager/client-capi/ckmc-manager.cpp index a5bebf4..7a4c8f1 100644 --- a/src/manager/client-capi/ckmc-manager.cpp +++ b/src/manager/client-capi/ckmc-manager.cpp @@ -816,3 +816,25 @@ int ckmc_remove_alias(const char *alias) int ret = mgr->removeAlias(alias); return to_ckmc_error(ret); } + +KEY_MANAGER_CAPI +int ckmc_encrypt_data(const ckmc_param_list_s */*params*/, + const char */*key_alias*/, + const char */*password*/, + const ckmc_raw_buffer_s /*decrypted*/, + ckmc_raw_buffer_s **/*ppencrypted*/) +{ + // TODO implement it + return CKMC_ERROR_UNKNOWN; +} + +KEY_MANAGER_CAPI +int ckmc_decrypt_data(const ckmc_param_list_s */*params*/, + const char */*key_alias*/, + const char */*password*/, + const ckmc_raw_buffer_s /* encrypted*/, + ckmc_raw_buffer_s **/*ppdecrypted*/) +{ + // TODO implement it + return CKMC_ERROR_UNKNOWN; +} diff --git a/src/manager/client-capi/ckmc-type.cpp b/src/manager/client-capi/ckmc-type.cpp index 7048333..d665dc0 100644 --- a/src/manager/client-capi/ckmc-type.cpp +++ b/src/manager/client-capi/ckmc-type.cpp @@ -33,13 +33,64 @@ #include #include #include +#include +namespace { -const char * const ckmc_label_name_separator = CKM::LABEL_NAME_SEPARATOR; -const char * const ckmc_label_shared_owner = CKM::LABEL_SYSTEM_DB; +const size_t DEFAULT_IV_LEN = 16; +const size_t DEFAULT_IV_LEN_BITS = 8*DEFAULT_IV_LEN; +const size_t DEFAULT_KEY_LEN_BITS = 4096; + +int _ckmc_random_buffer(ckmc_raw_buffer_s **buffer, size_t len) +{ + if(!buffer) + return CKMC_ERROR_INVALID_PARAMETER; + + char* data = static_cast(malloc(len*sizeof(char))); + if(!data) + return CKMC_ERROR_OUT_OF_MEMORY; + + std::ifstream is("/dev/urandom", std::ifstream::binary); + if(!is) { + free(data); + return CKMC_ERROR_FILE_SYSTEM; + } + + is.read(data, len); + if (static_cast(len) != is.gcount()) { + free(data); + return CKMC_ERROR_FILE_SYSTEM; + } + + return ckmc_buffer_new(reinterpret_cast(data), len, buffer); +} +int _ckmc_load_cert_from_x509(X509 *xCert, ckmc_cert_s **cert) +{ + if(xCert == NULL) { + return CKMC_ERROR_INVALID_FORMAT; + } -int _ckmc_load_cert_from_x509(X509 *xCert, ckmc_cert_s **cert); + BIO *bcert = BIO_new(BIO_s_mem()); + + i2d_X509_bio(bcert, xCert); + + CKM::RawBuffer output(8196); + int size = BIO_read(bcert, output.data(), output.size()); + BIO_free_all(bcert); + if (size <= 0) { + return CKMC_ERROR_INVALID_FORMAT; + } + output.resize(size); + + return ckmc_cert_new(output.data(), output.size(), CKMC_FORM_DER, cert); +} + +} // namespace anonymous + + +const char * const ckmc_label_name_separator = CKM::LABEL_NAME_SEPARATOR; +const char * const ckmc_label_shared_owner = CKM::LABEL_SYSTEM_DB; KEY_MANAGER_CAPI int ckmc_key_new(unsigned char *raw_key, size_t key_size, ckmc_key_type_e key_type, char *password, ckmc_key_s **ppkey) @@ -541,24 +592,94 @@ void ckmc_cert_list_all_free(ckmc_cert_list_s *first) } } -int _ckmc_load_cert_from_x509(X509 *xCert, ckmc_cert_s **cert) +KEY_MANAGER_CAPI +int ckmc_param_list_new(ckmc_param_list_s **ppparams) { - if(xCert == NULL) { - return CKMC_ERROR_INVALID_FORMAT; - } + if (!ppparams) + return CKMC_ERROR_INVALID_PARAMETER; - BIO *bcert = BIO_new(BIO_s_mem()); + *ppparams = reinterpret_cast(new(std::nothrow)(CKM::CryptoAlgorithm)); + if (!*ppparams) + return CKMC_ERROR_OUT_OF_MEMORY; + return CKMC_ERROR_NONE; +} - i2d_X509_bio(bcert, xCert); +KEY_MANAGER_CAPI +int ckmc_param_list_add_integer(ckmc_param_list_s *params, + ckmc_param_name_e name, + uint64_t value) +{ + if (!params) + return CKMC_ERROR_INVALID_PARAMETER; - CKM::RawBuffer output(8196); - int size = BIO_read(bcert, output.data(), output.size()); - BIO_free_all(bcert); - if (size <= 0) { - return CKMC_ERROR_INVALID_FORMAT; - } - output.resize(size); + CKM::CryptoAlgorithm* algo = reinterpret_cast(params); + bool ret = algo->addParam(static_cast(name), value); + return (ret ? CKMC_ERROR_NONE : CKMC_ERROR_INVALID_PARAMETER); +} - return ckmc_cert_new(output.data(), output.size(), CKMC_FORM_DER, cert); +KEY_MANAGER_CAPI +int ckmc_param_list_add_buffer(ckmc_param_list_s *params, + ckmc_param_name_e name, + const ckmc_raw_buffer_s *buffer) +{ + if (!params || !buffer || !buffer->data || buffer->size == 0) + return CKMC_ERROR_INVALID_PARAMETER; + + CKM::CryptoAlgorithm* algo = reinterpret_cast(params); + CKM::RawBuffer b(buffer->data, buffer->data + buffer->size); + bool ret = algo->addParam(static_cast(name), b); + return (ret ? CKMC_ERROR_NONE : CKMC_ERROR_INVALID_PARAMETER); } +KEY_MANAGER_CAPI +void ckmc_param_list_free(ckmc_param_list_s *params) +{ + CKM::CryptoAlgorithm* algo = reinterpret_cast(params); + delete algo; +} + +KEY_MANAGER_CAPI +int ckmc_generate_params(ckmc_algo_type_e type, ckmc_param_list_s *params) +{ + // return error if params are NULL + if(params == NULL) + return CKMC_ERROR_INVALID_PARAMETER; + + ckmc_raw_buffer_s* buffer = NULL; + int ret = CKMC_ERROR_NONE; + switch(type) + { + case CKMC_ALGO_AES_CTR: + ret = ckmc_param_list_add_integer(params, CKMC_PARAM_ED_CTR_LEN, DEFAULT_IV_LEN_BITS); + // no break on purpose + case CKMC_ALGO_AES_CBC: + case CKMC_ALGO_AES_GCM: + case CKMC_ALGO_AES_CFB: + if (ret == CKMC_ERROR_NONE) + ret = _ckmc_random_buffer(&buffer, DEFAULT_IV_LEN); + if (ret == CKMC_ERROR_NONE) + ret = ckmc_param_list_add_buffer(params, CKMC_PARAM_ED_IV, buffer); + else + ckmc_buffer_free(buffer); + break; + case CKMC_ALGO_RSA_OAEP: + break; + case CKMC_ALGO_RSA_SV: + case CKMC_ALGO_DSA_SV: + case CKMC_ALGO_ECDSA_SV: + // no hash, no padding by default + break; + case CKMC_ALGO_RSA_GEN: + case CKMC_ALGO_DSA_GEN: + ret = ckmc_param_list_add_integer(params, CKMC_PARAM_GEN_KEY_LEN, DEFAULT_KEY_LEN_BITS); + break; + case CKMC_ALGO_ECDSA_GEN: + ret = ckmc_param_list_add_integer(params, CKMC_PARAM_GEN_EC, CKMC_EC_PRIME192V1); + break; + default: + return CKMC_ERROR_INVALID_PARAMETER; + } + if (ret == CKMC_ERROR_NONE) + return ckmc_param_list_add_integer(params, CKMC_PARAM_ALGO_TYPE, type); + return ret; +} -- 2.7.4