+/*
+ * Network Configuration Module
+ *
+ * Copyright (c) 2000 - 2012 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 <stdlib.h>
+#include <glib.h>
+#include <ckmc/ckmc-type.h>
+#include <ckmc/ckmc-manager.h>
+#include <tizen.h>
+
+#include "log.h"
+#include "util.h"
+#include "wifi-key-encryption.h"
+
+#define KEY_ALIAS "connman_wifi_passphrase"
+#define IV_ALIAS "connman_wifi_enciv"
+#define AAD_ALIAS "connman_wifi_gcmaad"
+
+#define PASSPHRASE "Passphrase"
+#define RND_LENGTH 32
+#define AES_KEY_SIZE 256
+#define CKMC_ERROR_HANDLING(expression, release) err = expression; \
+ if (CKMC_ERROR_NONE != err) { \
+ err_str = get_error_message(err); \
+ ERR(#expression " : %s", err_str); \
+ release; \
+ return NULL; \
+ } \
+ DBG(#expression " success");
+
+static char* err_str;
+static int err;
+
+
+static void __netconfig_generate_random_bytes(unsigned char* bytes, int len)
+{
+ int i = 0;
+
+ srandom(time(NULL));
+
+ while (len--)
+ bytes[i++] = (unsigned char)random();
+
+}
+
+static void __netconfig_convert_hexstr_to_bytes(gchar* hexstr, int hlen, gchar* bin)
+{
+ hlen = hlen / 2;
+
+ while (hlen) {
+ if (*hexstr >= '0' && *hexstr <= '9')
+ *bin = (*hexstr - '0') << 4;
+ else if (*hexstr >= 'a' && *hexstr <= 'f')
+ *bin = (*hexstr - 'a' + 10) << 4;
+
+ hexstr++;
+
+ if (*hexstr >= '0' && *hexstr <= '9')
+ *bin |= (*hexstr - '0') & 0x0f;
+ else if (*hexstr >= 'a' && *hexstr <= 'f')
+ *bin |= (*hexstr - 'a' + 10) & 0x0f;
+
+ hexstr++;
+ bin++;
+ hlen--;
+ }
+}
+
+static void __netconfig_convert_bytes_to_hexstr(char* bin, int blen, gchar* hexstr)
+{
+ char t;
+
+ while (blen) {
+ t = (*bin >> 4) & 0x0f;
+
+ if (t >= 0 && t <= 9)
+ *hexstr = t + '0';
+ else if (t >= 10 && t <= 16)
+ *hexstr = (t - 10) + 'a';
+
+ hexstr++;
+
+ t = *bin & 0x0f;
+
+ if (t >= 0 && t <= 9)
+ *hexstr = t + '0';
+ else if (t >= 10 && t <= 16)
+ *hexstr = (t - 10) + 'a';
+
+ hexstr++;
+ bin++;
+ blen--;
+ }
+
+ *hexstr = '\0';
+}
+
+static int __netconfig_generate_aes_key()
+{
+ ckmc_policy_s pol;
+ pol.extractable = false;
+ pol.password = NULL;
+ int err;
+
+ err = ckmc_create_key_aes(AES_KEY_SIZE, KEY_ALIAS, pol);
+
+ if (err != CKMC_ERROR_NONE && err != CKMC_ERROR_DB_ALIAS_EXISTS)
+ return err;
+
+ return CKMC_ERROR_NONE;
+}
+
+static void* __netconfig_set_param_list_aes_gcm(ckmc_param_list_h param)
+{
+ ckmc_raw_buffer_s *iv_buf;
+ unsigned char rnd[RND_LENGTH];
+ ckmc_raw_buffer_s *aad_buf;
+ unsigned char aad[RND_LENGTH];
+
+ err = ckmc_get_data(IV_ALIAS, NULL, &iv_buf);
+
+ if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
+ ckmc_policy_s policy;
+ policy.extractable = true;
+ policy.password = NULL;
+
+ __netconfig_generate_random_bytes(rnd, RND_LENGTH);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_buffer_new(rnd, RND_LENGTH, &iv_buf),
+ NULL);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_save_data(IV_ALIAS, *iv_buf, policy),
+ ckmc_buffer_free(iv_buf));
+ }
+
+ err = ckmc_get_data(AAD_ALIAS, NULL, &aad_buf);
+
+ if (err == CKMC_ERROR_DB_ALIAS_UNKNOWN) {
+ ckmc_policy_s policy;
+ policy.extractable = true;
+ policy.password = NULL;
+
+ __netconfig_generate_random_bytes(aad, RND_LENGTH);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_buffer_new(aad, RND_LENGTH, &aad_buf),
+ ckmc_buffer_free(iv_buf));
+
+ CKMC_ERROR_HANDLING(
+ ckmc_save_data(AAD_ALIAS, *aad_buf, policy),
+ ckmc_buffer_free(iv_buf);\
+ ckmc_buffer_free(aad_buf));
+ }
+
+ CKMC_ERROR_HANDLING(
+ ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_IV, iv_buf),
+ ckmc_buffer_free(iv_buf);\
+ ckmc_buffer_free(aad_buf));
+
+ CKMC_ERROR_HANDLING(
+ ckmc_param_list_set_buffer(param, CKMC_PARAM_ED_AAD, aad_buf),
+ ckmc_buffer_free(iv_buf);\
+ ckmc_buffer_free(aad_buf));
+
+ return GINT_TO_POINTER(1);
+}
+
+gchar* _netconfig_encrypt_passphrase(const gchar *passphrase)
+{
+ gchar* origin_value = NULL;
+ gchar* encrypted_value = NULL;
+
+ ckmc_param_list_h param;
+ ckmc_raw_buffer_s *ptext;
+ ckmc_raw_buffer_s *ctext;
+
+ if (!passphrase)
+ return NULL;
+
+ origin_value = g_strdup(passphrase);
+
+ CKMC_ERROR_HANDLING(
+ __netconfig_generate_aes_key(),
+ g_free(origin_value));
+
+ CKMC_ERROR_HANDLING(
+ ckmc_generate_new_params(CKMC_ALGO_AES_GCM, ¶m),
+ g_free(origin_value));
+
+ if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
+ g_free(origin_value);
+ return NULL;
+ }
+
+ CKMC_ERROR_HANDLING(
+ ckmc_buffer_new((unsigned char*)origin_value,
+ strlen((char*)origin_value) + 1, &ptext),
+ ckmc_param_list_free(param);\
+ g_free(origin_value));
+
+ CKMC_ERROR_HANDLING(
+ ckmc_encrypt_data(param, KEY_ALIAS, NULL, *ptext, &ctext),
+ ckmc_param_list_free(param);\
+ ckmc_buffer_free(ptext);\
+ g_free(origin_value));
+
+ if ((encrypted_value = g_try_malloc0(ctext->size * 2 + 1)) == NULL) {
+ DBG(" encrypted_value allocation failed");
+ ckmc_param_list_free(param);
+ ckmc_buffer_free(ptext);
+ ckmc_buffer_free(ctext);
+ g_free(origin_value);
+ return NULL;
+ }
+
+ __netconfig_convert_bytes_to_hexstr((char*)ctext->data, ctext->size, encrypted_value);
+
+ g_free(origin_value);
+
+ ckmc_param_list_free(param);
+ ckmc_buffer_free(ptext);
+ ckmc_buffer_free(ctext);
+
+ return encrypted_value;
+}
+
+static gchar* _netconfig_decrypt_passphrase(const gchar *enc_data)
+{
+ gchar *ehexstr = NULL;
+ gchar *encrypted_value = NULL;
+ gchar *passphrase = NULL;
+
+ ckmc_param_list_h param = NULL;
+ ckmc_raw_buffer_s *ptext;
+ ckmc_raw_buffer_s *ctext;
+
+ if (!enc_data)
+ return NULL;
+
+ ehexstr = g_strdup(enc_data);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_generate_new_params(CKMC_ALGO_AES_GCM, ¶m),
+ g_free(ehexstr));
+
+ if (__netconfig_set_param_list_aes_gcm(param) == NULL) {
+ g_free(ehexstr);
+ return NULL;
+ }
+
+ if ((encrypted_value = g_try_malloc0(strlen((char*)ehexstr)/2)) == NULL) {
+ DBG(" encrypted_value allocation failed");
+ ckmc_param_list_free(param);
+ g_free(ehexstr);
+ return NULL;
+ }
+
+ __netconfig_convert_hexstr_to_bytes(ehexstr, strlen((char*)ehexstr), encrypted_value);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_buffer_new((unsigned char*)encrypted_value,
+ strlen((char*)ehexstr)/2, &ctext),
+ ckmc_param_list_free(param);\
+ g_free(encrypted_value);\
+ g_free(ehexstr));
+
+ g_free(ehexstr);
+
+ CKMC_ERROR_HANDLING(
+ ckmc_decrypt_data(param, KEY_ALIAS, NULL, *ctext, &ptext),
+ ckmc_param_list_free(param);\
+ ckmc_buffer_free(ctext);\
+ g_free(encrypted_value));
+
+ passphrase = g_strdup((const gchar*)ptext->data);
+
+ ckmc_param_list_free(param);
+ ckmc_buffer_free(ctext);
+ ckmc_buffer_free(ptext);
+ g_free(encrypted_value);
+
+ return passphrase;
+}
+
+gboolean handle_encrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *passphrase)
+{
+ gchar *enc_data = NULL;
+
+ if ((wifi == NULL) || (passphrase == NULL)) {
+ ERR("Invalid parameter");
+ netconfig_error_invalid_parameter(context);
+ return FALSE;
+ }
+
+ enc_data = _netconfig_encrypt_passphrase(passphrase);
+
+ if (!enc_data) {
+ ERR("Failed to encrypt the passphrase");
+ netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
+ return FALSE;
+ }
+
+ wifi_complete_encrypt_passphrase(wifi, context, enc_data);
+ g_free(enc_data);
+
+ return TRUE;
+}
+
+gboolean handle_decrypt_passphrase(Wifi *wifi, GDBusMethodInvocation *context, const gchar *enc_data)
+{
+ gchar *passphrase = NULL;
+
+ if ((wifi == NULL) || (enc_data == NULL)) {
+ ERR("Invalid parameter");
+ netconfig_error_invalid_parameter(context);
+ return FALSE;
+ }
+
+ passphrase = _netconfig_decrypt_passphrase(enc_data);
+
+ if (!passphrase) {
+ ERR("Failed to decrypt the passphrase");
+ netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "OperationFailed");
+ return FALSE;
+ }
+
+ wifi_complete_decrypt_passphrase(wifi, context, passphrase);
+ g_free(passphrase);
+
+ return TRUE;
+}
+