/* * Copyright (c) 2016 - 2019 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 * * * @file crypto_service.c * @author Dongsun Lee (ds73.lee@samsung.com) * @version 1.0 * @brief provides encryption and decription operations. */ #include "crypto_service.h" #include #include #include #include #include #include #include #include #include #include "web_app_enc.h" #include "wae_log.h" #define AES_256_KEY_SIZE 32 #define KEK_IV_LEN 16 #define PBKDF2_ITERATION 1024 crypto_element_s *dek_kek = NULL; int _generate_dek_kek() { int ret = WAE_ERROR_NONE; raw_buffer_s *kek = NULL; raw_buffer_s *iv = NULL; kek = buffer_create(AES_256_KEY_SIZE); if (kek == NULL) { ret = WAE_ERROR_MEMORY; goto error; } iv = buffer_create(KEK_IV_LEN); if (iv == NULL) { ret = WAE_ERROR_MEMORY; goto error; } ret = PKCS5_PBKDF2_HMAC_SHA1( DEK_KEK_SEED, -1, NULL, 0, PBKDF2_ITERATION, AES_256_KEY_SIZE, kek->buf); if (ret == 0) { ret = WAE_ERROR_CRYPTO; goto error; } else { ret = WAE_ERROR_NONE; } dek_kek = crypto_element_create(kek, iv); error: if (ret != WAE_ERROR_NONE) { if (kek != NULL) buffer_destroy(kek); if (iv != NULL) buffer_destroy(iv); } return ret; } int encrypt_preloaded_app_dek(const raw_buffer_s *dek, raw_buffer_s **pencrypted_dek) { int ret = WAE_ERROR_NONE; if (dek_kek == NULL) { ret = _generate_dek_kek(); if (ret != WAE_ERROR_NONE) return ret; } return encrypt_aes_cbc(dek_kek, dek, pencrypted_dek); } int decrypt_preloaded_app_dek(const raw_buffer_s *encrypted_dek, raw_buffer_s **pdek) { int ret = WAE_ERROR_NONE; if (dek_kek == NULL) { ret = _generate_dek_kek(); if (ret != WAE_ERROR_NONE) return ret; } return decrypt_aes_cbc(dek_kek, encrypted_dek, pdek); } int encrypt_aes_cbc(const crypto_element_s *ce, const raw_buffer_s *data, raw_buffer_s **pencrypted_data) { if (!is_crypto_element_valid(ce) || !is_buffer_valid(data) || pencrypted_data == NULL) return WAE_ERROR_INVALID_PARAMETER; EVP_CIPHER_CTX *ctx = NULL; int len = 0; raw_buffer_s *encrypted_data = NULL; int ret = WAE_ERROR_NONE; WAE_SLOGI("Encryption Started. size=%zu", data->size); /* check input paramter */ if (ce->dek->size != 32) { WAE_SLOGE("Encryption Failed. Invalid Key Length. key_len=%zu", ce->dek->size); return WAE_ERROR_INVALID_PARAMETER; } // assing a enough memory for decryption. encrypted_data = buffer_create(data->size + 32); if (encrypted_data == NULL) { ret = WAE_ERROR_MEMORY; goto error; } /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) { WAE_SLOGE("Encryption Failed. EVP_CIPHER_CTX_new failed"); ret = WAE_ERROR_CRYPTO; goto error; } /* Initialise the encryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if (EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, ce->dek->buf, ce->iv->buf) != 1) { WAE_SLOGE("Encryption Failed. EVP_EncryptInit_ex failed"); ret = WAE_ERROR_CRYPTO; goto error; } /* Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ len = encrypted_data->size; if (EVP_EncryptUpdate(ctx, encrypted_data->buf, &len, data->buf, data->size) != 1) { WAE_SLOGE("Encryption Failed. EVP_EncryptUpdate failed"); ret = WAE_ERROR_CRYPTO; goto error; } encrypted_data->size = len; /* Finalise the encryption. Further encrypted data bytes may be written at * this stage. */ if (EVP_EncryptFinal_ex(ctx, encrypted_data->buf + encrypted_data->size, &len) != 1) { WAE_SLOGE("Encryption Failed. EVP_EncryptFinal_ex failed"); ret = WAE_ERROR_CRYPTO; goto error; } encrypted_data->size += len; *pencrypted_data = encrypted_data; WAE_SLOGI("Encryption Ended Successfully. encrypted_len: %zu", encrypted_data->size); error: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ret != WAE_ERROR_NONE) buffer_destroy(encrypted_data); return ret; } int decrypt_aes_cbc(const crypto_element_s *ce, const raw_buffer_s *encrypted_data, raw_buffer_s **pdata) { if (!is_crypto_element_valid(ce) || !is_buffer_valid(encrypted_data) || pdata == NULL) return WAE_ERROR_INVALID_PARAMETER; EVP_CIPHER_CTX *ctx = NULL; int len = 0; raw_buffer_s *data = NULL; int ret = WAE_ERROR_NONE; WAE_SLOGI("Decryption Started. size=%zu", encrypted_data->size); /* check input paramter */ if (ce->dek->size != 32) { WAE_SLOGE("Decryption Failed. Invalid Key Length. key_len=%zu", ce->dek->size); return WAE_ERROR_INVALID_PARAMETER; } // assing a enough memory for decryption. data = buffer_create(encrypted_data->size); if (data == NULL) { ret = WAE_ERROR_MEMORY; goto error; } /* Create and initialise the context */ if (!(ctx = EVP_CIPHER_CTX_new())) { WAE_SLOGE("Decryption Failed. EVP_CIPHER_CTX_new failed"); ret = WAE_ERROR_CRYPTO; goto error; } /* Initialise the decryption operation. IMPORTANT - ensure you use a key * and IV size appropriate for your cipher * In this example we are using 256 bit AES (i.e. a 256 bit key). The * IV size for *most* modes is the same as the block size. For AES this * is 128 bits */ if (EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, ce->dek->buf, ce->iv->buf) != 1) { WAE_SLOGE("Decryption Failed. EVP_DecryptInit_ex failed"); ret = WAE_ERROR_CRYPTO; goto error; } /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ len = data->size; if (EVP_DecryptUpdate(ctx, data->buf, &len, encrypted_data->buf, encrypted_data->size) != 1) { WAE_SLOGE("Decryption Failed. EVP_DecryptUpdate failed"); ret = WAE_ERROR_CRYPTO; goto error; } data->size = len; /* Finalise the decryption. Further plaintext bytes may be written at * this stage. */ if (EVP_DecryptFinal_ex(ctx, data->buf + data->size, &len) != 1) { WAE_SLOGE("Decryption Failed. EVP_DecryptFinal_ex failed"); ret = WAE_ERROR_CRYPTO; goto error; } data->size += len; *pdata = data; WAE_SLOGI("Decryption Ended Successfully. decrypted_len: %zu", data->size); error: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ret != WAE_ERROR_NONE) buffer_destroy(data); return ret; }