Security/Tizen 3.X Key Manager encryption/decryption support

From Tizen Wiki
Jump to: navigation, search

Requirements

  • key-manager shall support securely storing symmetric and asymmetric keys.
  • Applications and internal modules shall be able to store their keys securely.
  • Support for crypto operation: encrypt/decrypt with symetric and asymetric keys
    • for items not defined here, refer to the w3c crypto API.

High level design

Overview

The purpose of this feature is to support data encryption and decryption using keys stored in key-manager but without disclosing them to the client.

Aes hld.png

Encryption/decryption algorithms

The following encryption algorithms will be supported (based on W3C WebCryptoAPI):

  • AES-CTR
  • AES-CBC
  • AES-GCM
  • AES-CFB
  • RSA-OAEP

Responsiveness

Encryption and decryption of large data can take a significant amount of time and make key-manager service unresponsive during such operations. This is because in current architecture only one thread is allowed to use internal database. To overcome this issue another service running in separate thread will be introduced. The service will be responsible for time consuming encryption and decryption. It will communicate with CKM service to retrieve key from database and perform encryption & decryption. To make communication between services possible a Communication Manager will be introduced. It will allow services to register as listener for certain messages and to send them.

Thread safety

Messages received from Communication Manager will be added to a service internal message queue. The queue access will be synchronized.

Data transfer

Encrypted/decrypted data can be large (order of MBs). For now we'll assume that data will fit into memory. If not, then the operation will fail. To transfer the data and the result between client and the server we'll have to split it in smaller parts. When server collects all data it may start encryption/decryption process. When client collects all data it may respond to the client. The operation will fail if a part of data won't reach its destination within a certain time limit.

Use case

Encrypting/decrypting data:

  1. Encryption Service registers in Connection Manager as a listener of RequestKey.
  2. CKM Service registers in Connection Manager as a listener of ResponseKey.
  3. Client asks Encryption Service for data encryption/decryption with key K.
  4. Encryption Service sends RequestKey to Communication Manager asking for key K.
  5. CKM Service receives notification and reads the key from DB. It can also refuse to do so if the client has not sufficient permissions or the key does not exist.
  6. CKM Service responds with ResponseKey containing the key K.
  7. Encryption Service performs encryption/decryption of data and returns the result to the client.

AES support

To implement this feature AES support in key-manager is required.

Detailed Design

Required changes:

API

/usr/include/ckmc/ckmc-type.h

 /**
 * @brief Enumeration for crypto algorithm types.
 * @since_tizen 3.0
 */
 typedef enum__ckmc_algo_type {
    CKMC_ALGO_AES_CTR = 0,              /**< AES-CTR algorithm */
    CKMC_ALGO_AES_CBC,                  /**< AES-CBC algorithm */
    CKMC_ALGO_AES_GCM,                  /**< AES-GCM algorithm */
    CKMC_ALGO_AES_CFB,                  /**< AES-CFB algorithm */
    CKMC_ALGO_RSA_OAEP                  /**< RSA-OAEP algorithm */
} ckmc_algo_type_e;

/**
 * @brief The structure for AES CTR algorithm params
 * @since_tizen 3.0
 */
typedef struct __ckmc_algo_param_aes_ctr {
    unsigned char counter[16];          /**< length bits of counter (rightmost) + nonce */
    unsigned char length;               /**< length in bits of the counter */
} ckmc_algo_param_aes_ctr_s;

/**
 * @brief The structure for AES CBC algorithm params
 * @since_tizen 3.0
 */
typedef struct __ckmc_algo_param_aes_cbc {
    unsigned char iv[16];               /**< initialization vector */
} ckmc_algo_param_aes_cbc_s;

/**
 * @brief The structure for AES GCM algorithm params
 * @since_tizen 3.0
 */
typedef struct __ckmc_algo_param_aes_gcm {
    unsigned long long iv_length;       /**< length of the initalization vector */
    unsigned long long aad_length;      /**< length of additional authentication data */
    const unsigned char* iv;            /**< initialization vector - up to 2^64-1 bytes long */
    const unsigned char* aad;           /**< optional additional auth data */
    unsigned char tag_length;           /**< length of the authentication tag in bits:
                                             32, 64, 96, 104, 112, 120 or 128 (the first tag_length
                                             bits of the cipher text are the tag*/
} ckmc_algo_param_aes_gcm_s;

/**
 * @brief The structure for AES CFB algorithm params
 * @since_tizen 3.0
 */
typedef struct __ckmc_algo_param_aes_cfb {
    unsigned char iv[16];         /**< initialization vector */
} ckmc_algo_param_aes_cfb_s;

/**
 * @brief The structure for RSA OAEP algorithm params
 * @since_tizen 3.0
 */
typedef struct __ckmc_algo_param_rsa_oaep {
    unsigned long long label_length;    /**< label length */
    const unsigned char* label;         /**< optional label to associate with the data */
} ckmc_algo_param_rsa_oaep_s;

/**
 * @brief The structure describing encryption/decryption algorithm
 * @since_tizen 3.0
 */
typedef struct __ckmc_encryption_algo {
    ckmc_algo_type_e type;              /**< algorithm type */
    union {
        ckmc_algo_param_aes_ctr_s param_aes_ctr;
        ckmc_algo_param_aes_cbc_s param_aes_cbc;
        ckmc_algo_param_aes_gcm_s param_aes_gcm;
        ckmc_algo_param_aes_cfb_s param_aes_cfb;
        ckmc_algo_param_rsa_oaep_s param_rsa_oaep;
    };
} ckmc_encryption_algo_s;

/**
 * @brief Generates algorithm parameters for a given algorithm type
 *
 * @since_tizen 3.0
 *
 * @remarks Caller is responsible for ckmc_encryption_algo_s creation and destruction.
 * @remarks Algorithm parameters used for encryption could be then used for decryption. This
 *          function should not be used for generating decryption parameters.
 * @remarks Algorithm parameters are set to default values. Optional fields are left empty.
 *          Initialization vectors are randomly generated. Pointers in ckmc_encryption_algo_s
 *          structure are allocated using malloc(). Caller is responsible for freeing them. Calling
 *          this function twice without freeing them will result in memory leak.
 *
 * @param[in] type      Type of the algorithm
 * @param[out] algo     Default algorithm description structure
 *
 * @return @c 0 on success, otherwise a negative error value
 *
 * @retval #CKMC_ERROR_NONE                 Successful
 * @retval #CKMC_ERROR_INVALID_PARAMETER    Input parameter is invalid
 */
int ckmc_generate_params(ckmc_algo_type_e type, ckmc_encryption_algo_s* algo);

/usr/include/ckmc/ckmc-manager.h

/**
 * @brief Encrypts data using selected key and algorithm.
 *
 * @since_tizen 3.0
 *
 * @remarks Key identified by @a key_alias should exist.
 *
 * @param[in] params            Algorithm parameter list handle. See #ckmc_param_list_h and
 *                              #ckmc_algo_type_e for details
 * @param[in] key_alias         Alias of the key to be used for encryption
 * @param[in] password          The password used in decrypting a key value \n
 *                              If password of policy is provided in ckmc_save_key(), the same
 *                              password should be provided
 * @param[in] decrypted         Data to be encrypted. In case of AES algorithm there are no
 *                              restrictions on the size of data. For RSA the size must be smaller
 *                              or equal to <key_size_in bytes> - 42. Example: for 1024 RSA key the
 *                              maximum data size is 1024/8 - 42 = 86.
 * @param[out] ppencrypted      Encrypted data (some algorithms may return additional information
 *                              embedded in encrypted data. AES GCM is an example) \n
 *                              The caller is responsible for freeing @a encrypted 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 (missing or invalid
 *                                          mandatory algorithm parameter, decrypted = NULL,
 *                                          ppencrypted = NULL)
 * @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.
 *
 * @see ckmc_buffer_free()
 * @see ckmc_param_list_new()
 * @see ckmc_param_list_free()
 * @see ckmc_param_list_set_integer()
 * @see ckmc_param_list_set_buffer()
 * @see ckmc_generate_new_params()
 * @see #ckmc_param_list_h
 * @see #ckmc_param_name_e
 * @see #ckmc_algo_type_e
 */
int ckmc_encrypt_data(ckmc_param_list_h 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
 *
 * @remarks Key identified by @a key_alias should exist.
 *
 * @param[in] params            Algorithm parameter list handle. You should use the same parameters
 *                              that were used for encryption. See #ckmc_param_list_h and
 *                              #ckmc_algo_type_e for details
 * @param[in] key_alias         Alias of the key to be used for encryption
 * @param[in] password          The password used in decrypting a key value \n
 *                              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 \n
 *                              The caller is responsible for freeing @a decrypted 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 (missing or invalid
 *                                          mandatory algorithm parameter, encrypted = NULL,
 *                                          ppdecrypted = NULL)
 * @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.
 *
 * @see ckmc_buffer_free()
 * @see ckmc_param_list_new()
 * @see ckmc_param_list_free()
 * @see ckmc_param_list_set_integer()
 * @see ckmc_param_list_set_buffer()
 * @see ckmc_generate_new_params()
 * @see #ckmc_param_list_h
 * @see #ckmc_param_name_e
 * @see #ckmc_algo_type_e
 */
int ckmc_decrypt_data(ckmc_param_list_h params,
                      const char *key_alias,
                      const char *password,
                      const ckmc_raw_buffer_s encrypted,
                      ckmc_raw_buffer_s **ppdecrypted);

Inter service communication

CKMService will be responsible for database access and for handling inter service database requests issued by other services like EncryptionService.

State diagram

Encryption state diagram.png

Class diagram

Inter service classes.png Inter service msg class.png

Sequence diagram

Inter service sequence.png

Encryption/decryption service

Encryption service is responsible for performing encryption/decryption operations with keys stored in the database. To retrieve them it uses inter service communication.

Algorithms

  • AES algorithms are implemented using Cipher::EvpCipherWrapper, appropriate EVP_CIPHER and additional algorithm params passed with Cipher::Base::Control method.
    • In case of AES GCM there's a possibility to include Additional Authentication Data (AAD). This is realized by calling EvpCipherWrapper::Append with AAD as argument and ignoring the output data prior to appending plain text.
    • Other AES modes require only IV which is passed during EvpCipherWrapper construction.
    • AES CTR requires splitting IV into counter and a nonce depending on the length attribute. This is however unsupported by openssl and thus whole IV will be treated as counter.
  • RSA OAEP uses different openssl API for encryption/decryption and is implemented in a separate class.

Cipher classes.png

Params serialization

Algorithm configuration is implemented as CryptoAlgorithm class. The class holds the algorithm type and a map of parameters names to their values. Each of these parameters is a buffer or a integer. Depending on the parameter name the proper type interpretation should be used. Parameters can be used for encryption/decryption, key generation and signing/verification operations. CryptoAlgorithmSerializable is responsible for serialization/deserialization.

Crypto params classes.png

Service

EncryptionService is responsible for registering inter service communication callbacks, and socket communication. It holds an instance of EncryptionLogic and notifies it about messages coming from SocketManager and CommunicationManager. EncryptionLogic is holding a map of requests received from client. Each request holds encryption parameters, client identifiers, and an id of a message sent to ckm-service. EncryptionLogic has an interface to EncryptionService that allows inter service communication (asking for a key) and responding asynchronously to the client when crypto operation is finished.

Encryption service classes.png