#include "system/includes.h" #include "json_c/json_object.h" #include "common/base64.h" #include "common/aes.h" #include "sock_api/sock_api.h" #include "lwip.h" #include "wifi/wifi_connect.h" #include "mbedtls/aes.h" #include "mbedtls/dhm.h" #include "mbedtls/rsa.h" #include "mbedtls/sha1.h" #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" #include "time.h" #include #if 1 #define log_info(x, ...) printf("\n\n>>>>>>[aplink_test]" x " ", ## __VA_ARGS__) #else #define log_info(...) #endif #define DH_INFO "{\"type\":\"dh\",\"sequence\":2,\"data\":{\"dh_key\":\"%s\",\"dh_p\":\"%s\",\"dh_g\":\"%s\"}}" #define KEYNGREQ 0x01 #define DH 0x02 #define QPLINK 0x03 #define ACK 0x04 #define ELINK_SRV_PORT 32769 //服务器端口 #define IOT_SSID "ChinaIOT-%s-%02X%02X" //ssid格式 #define IOT_PWD "" //AP模式下登录密码,这里不设置密码 #define VENDOR "Vendor" //设备厂商 extern struct json_object *json_tokener_parse(const char *str); const static int iot_device_send_keyngack(char *buf, int buf_len); const static int iot_device_send_dh(char *buf, int buf_len); const static int iot_device_send_aplinkget(char *buf, int buf_len); static int dh_base64_decode(const unsigned char *input, unsigned char *output); static int ap_elink_start(void); void Hex2Str(const unsigned char *hex, char *str, int len); static int dh_base64_encode(const unsigned char *input, const int len, unsigned char *output); static int calculate_common_key(mbedtls_dhm_context *context, unsigned char *srv_pub, char *out_put); static void iot_interact_to_app(void *client_sock); static int aes_cbc_encode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *encode_buf); static int aes_cbc_decode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *decode_buf); static int iot_device_rec_handle(const char *object); static int aplink_sock_write(void *sockhdl, const char *buf, size_t n); extern int elink_aplink_set_ssid_pwd(const char *ssid, const char *pwd); extern void get_wifi_mac_addr(u8 *mac_addr); static void iot_device_enter_ap_mode(void); static int flag; typedef enum { aplink_idel_state = 1, aplink_wait_keyngreq, aplink_wait_dh_info, aplink_wait_aplink_info, aplink_wait_ack, aplink_qlink_finish, } aplink_state; typedef enum { aplink_receive_keyngreq = 1, aplink_receive_dh_info, aplink_receive_aplink_info, aplink_receive_ack, } aplink_event; typedef struct { aplink_state curState; aplink_event event; const int (*aplink_action)(char *, int); aplink_state nextState; } aplink_state_change; typedef struct { aplink_state curState; int stuNum; aplink_state_change *form; } elink_aplink; typedef struct _iot_device_info { unsigned char common_key[16]; char ssid[32]; char pwd[32]; unsigned char dh_key[36]; unsigned char dh_p[36]; unsigned char dh_g[12]; mbedtls_dhm_context dhm_cli; elink_aplink e_aplink; aplink_event e_event; int protected; } iot_device_info; typedef struct _iot_rec_type { char *rec_string; uint8_t type; } iot_rec_type; static iot_device_info iot_device_local; static mbedtls_ctr_drbg_context ctr_drbg; static const char aplink_ver[] = "V1.0"; static void *ap_elink_sock = NULL; static void *cli_sock = NULL; static int aplink_get_ssid_pwd_success = 0; static int local_pid = 0; static iot_rec_type type_table[] = { {"keyngreq", KEYNGREQ}, {"dh", DH}, {"aplink", QPLINK}, {"ack", ACK}, {NULL, 0} }; //State Table : 当前状态 激发事件 回调函数 下一个状态 static aplink_state_change aplink_table[] = { {aplink_idel_state, aplink_receive_keyngreq, iot_device_send_keyngack, aplink_wait_dh_info}, {aplink_wait_dh_info, aplink_receive_dh_info, iot_device_send_dh, aplink_wait_aplink_info}, {aplink_wait_aplink_info, aplink_receive_aplink_info, iot_device_send_aplinkget, aplink_wait_ack}, {aplink_wait_ack, aplink_receive_ack, NULL, aplink_qlink_finish}, }; const char *aplink_version(void) { return aplink_ver; } void Hex2Str(const unsigned char *hex, char *str, int len) { int i; char temp[3]; for (i = 0; i < len; i++) { sprintf(temp, "%02X", (unsigned char)hex[i]); memcpy(&str[i * 2], temp, 2); } str[2 * len] = '\0'; } static void aplink_state_transFer(elink_aplink *aplink, aplink_state state) { aplink->curState = state; } static int aplink_sock_write(void *sockhdl, const char *buf, size_t n) { size_t nLeft = n; size_t nWrite = 0; int ret; while (nLeft > 0) { ret = sock_send(sockhdl, buf + nWrite, nLeft, 0); if (ret != nLeft) { log_info("aplink_sock_write error occurred:%d\n", sock_get_error(sockhdl)); break; } else { nLeft -= ret; nWrite += ret; } } return nWrite == n ? n : -1; } static int aplink_eventHandle(elink_aplink *aqlink, const aplink_event event, void *parm) { aplink_state_change *changeTable = aqlink->form; const int (*aplink_action)(char *, int) = NULL; aplink_state nextState; aplink_state curState = aqlink->curState; unsigned something_happen = 0; unsigned int i; unsigned int ret; char send_buf[512]; unsigned int len; void *cli_sock = parm; for (i = 0; i < aqlink->stuNum; i++) { if (event == changeTable[i].event && curState == changeTable[i].curState) { aplink_action = changeTable[i].aplink_action; nextState = changeTable[i].nextState; something_happen = 1; break; } } if (something_happen) { if (aplink_action != NULL) { len = aplink_action(send_buf, sizeof(send_buf)); if (len == -1) { return -1; } os_time_dly(50); ret = aplink_sock_write(cli_sock, send_buf, len); if (ret == -1) { log_info("sock_sendto err!!!"); return -1; } } aplink_state_transFer(aqlink, nextState); something_happen = 0; } return 0; } static void aplink_init(elink_aplink *aqlink, aplink_state curState, const int num, aplink_state_change *form) { aqlink->form = form; aqlink->stuNum = num; aqlink->curState = curState; return; } static int dh_calculate_public_key(mbedtls_dhm_context *context, const char *p, const char *g, unsigned char *public) { int ret = 0; const char *pers = "aplink"; unsigned char cli_pub[16]; mbedtls_entropy_context entropy; mbedtls_dhm_init(context); mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&ctr_drbg); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *) pers, strlen(pers))) != 0) { mbedtls_printf("error!!! mbedtls_ctr_drbg_seed returned %d\n", ret); goto EXIT; } mbedtls_mpi_read_string(&(context->P), 16, p); mbedtls_mpi_read_string(&(context->G), 10, g); context->len = mbedtls_mpi_size(&(context->P)); ret = mbedtls_dhm_make_public(context, 16, cli_pub, sizeof(cli_pub), mbedtls_ctr_drbg_random, &ctr_drbg); if (ret != 0) { mbedtls_printf(" error!!! mbedtls_dhm_make_public %d\n", ret); goto EXIT; } memcpy(public, cli_pub, sizeof(cli_pub)); mbedtls_entropy_free(&entropy); /* mbedtls_ctr_drbg_free(&ctr_drbg); */ return 0; EXIT: mbedtls_dhm_free(context); mbedtls_entropy_free(&entropy); mbedtls_ctr_drbg_free(&ctr_drbg); return -1; } void aplink_cfg_start(void) { iot_device_enter_ap_mode(); } static void wifi_set_lan_setting_info(void) { struct lan_setting lan_setting_info = { .WIRELESS_IP_ADDR0 = 192, .WIRELESS_IP_ADDR1 = 168, .WIRELESS_IP_ADDR2 = 1, .WIRELESS_IP_ADDR3 = 1, .WIRELESS_NETMASK0 = 255, .WIRELESS_NETMASK1 = 255, .WIRELESS_NETMASK2 = 255, .WIRELESS_NETMASK3 = 0, .WIRELESS_GATEWAY0 = 192, .WIRELESS_GATEWAY1 = 168, .WIRELESS_GATEWAY2 = 1, .WIRELESS_GATEWAY3 = 1, .SERVER_IPADDR1 = 192, .SERVER_IPADDR2 = 168, .SERVER_IPADDR3 = 1, .SERVER_IPADDR4 = 1, .CLIENT_IPADDR1 = 192, .CLIENT_IPADDR2 = 168, .CLIENT_IPADDR3 = 1, .CLIENT_IPADDR4 = 2, .SUB_NET_MASK1 = 255, .SUB_NET_MASK2 = 255, .SUB_NET_MASK3 = 255, .SUB_NET_MASK4 = 0, }; net_set_lan_info(&lan_setting_info); } static void iot_device_enter_ap_mode(void) { u8 mac[6]; char device_mac[32]; wifi_get_mac(mac); sprintf(device_mac, IOT_SSID, VENDOR, mac[0], mac[1]); log_info("aplink ssid: %s", device_mac); wifi_set_lan_setting_info(); //STA转AP模式,需要重新配置一下IP信息和DHCP池起始分配地址 wifi_enter_ap_mode(device_mac, IOT_PWD); ap_elink_start(); } /* void iot_device_enter_sta_mode(const char *ssid, const char *pwd) */ void iot_device_enter_sta_mode(char *ssid, char *pwd) { wifi_set_sta_connect_timeout(0); wifi_enter_sta_mode(ssid, pwd); wifi_store_mode_info(STA_MODE, ssid, pwd); } static void ap_elink_tcp_init(void *priv) { struct sockaddr_in client_addr; socklen_t socketLength = sizeof(struct sockaddr_in); ap_elink_sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL); if (ap_elink_sock == NULL) { log_info("ap_elink_tcp_init socket error"); goto EXIT; } if (sock_set_reuseaddr(ap_elink_sock)) { log_info("sock_set_reuseaddr error"); goto EXIT; } struct sockaddr _ss; struct sockaddr_in *dest_addr = (struct sockaddr_in *)&_ss; dest_addr->sin_family = AF_INET; dest_addr->sin_addr.s_addr = htonl(INADDR_ANY); dest_addr->sin_port = htons(ELINK_SRV_PORT); if (sock_bind(ap_elink_sock, (struct sockaddr *)&_ss, sizeof(_ss))) { log_info("ap_elink_tcp_init bind error"); goto EXIT; } if (sock_listen(ap_elink_sock, 5)) { log_info("ap_elink_tcp_init sock_listen error"); goto EXIT; } log_info("sock_accept starting......................"); cli_sock = sock_accept(ap_elink_sock, (struct sockaddr *)&client_addr, &socketLength, NULL, NULL); flag = 0; if (cli_sock == NULL) { log_info("ap_elink_tcp_init sock_accept error"); goto EXIT; } log_info("Successfully connected. Network configuration is starting!!!....................."); memset(&iot_device_local, 0, sizeof(iot_device_info)); aplink_init(&(iot_device_local.e_aplink), aplink_idel_state, sizeof(aplink_table) / sizeof(aplink_state_change), aplink_table); extern int wifi_is_on(void); while (wifi_is_on() == 0) { os_time_dly(1); } iot_interact_to_app(cli_sock); if (ap_elink_sock) { sock_unreg(ap_elink_sock); ap_elink_sock = NULL; } EXIT: if (ap_elink_sock) { sock_unreg(ap_elink_sock); ap_elink_sock = NULL; } } static int ap_elink_start(void) { if (thread_fork("ap_elink_tcp_init", 17, 2024, 0, &local_pid, ap_elink_tcp_init, NULL) != OS_NO_ERR) { return -1; } return 0; } static void iot_interact_to_app(void *client_sock) { int recv_len = 0; unsigned char recv_buf[1024] = {0}; unsigned char decode_buf[512] = {0}; int decode_len = 0; int err = 0; for (;;) { recv_len = sock_recvfrom(client_sock, recv_buf, sizeof(recv_buf), 0, NULL, NULL); if ((recv_len != -1) && (recv_len != 0)) { if (iot_device_local.protected) { /* put_buf(recv_buf, recv_len); */ decode_len = aes_cbc_decode(recv_buf + 8, recv_len - 8, iot_device_local.common_key, decode_buf); decode_buf[decode_len] = '\0'; /* put_buf(iot_device_local.common_key, 16); */ log_info("recv string : %s", decode_buf); err = iot_device_rec_handle((char *)decode_buf); if (err == -1) { log_info("iot_device_rec_handle err!!!\n"); goto EXIT; } } else { recv_buf[recv_len] = '\0'; log_info("recv string : %s", recv_buf + 8); err = iot_device_rec_handle((char *)(recv_buf + 8)); if (err == -1) { log_info("iot_device_rec_handle err!!!\n"); goto EXIT; } } memset(recv_buf, 0, sizeof(recv_buf)); os_time_dly(30); } else { log_info("sock_recvfrom err!!!"); goto EXIT; } err = aplink_eventHandle(&(iot_device_local.e_aplink), iot_device_local.e_event, client_sock); if (err == -1) { log_info("aplink_eventHandle err!!!\n"); goto EXIT; } /* if(iot_device_local.e_aplink.curState == aplink_qlink_finish) */ if (iot_device_local.e_aplink.curState == aplink_wait_ack) { break; } } aplink_get_ssid_pwd_success = 1; log_info("Successfully obtained distribution network information.Connecting to network.........."); log_info("get ssid: %s, pwd: %s", iot_device_local.ssid, iot_device_local.pwd); elink_aplink_set_ssid_pwd(iot_device_local.ssid, iot_device_local.pwd); EXIT: /* sock_unreg(client_sock); */ if (!aplink_get_ssid_pwd_success) { log_info("Failed to connect to the Internet, please help me connect to the Internet again"); } aplink_get_ssid_pwd_success = 0; } const static uint8_t check_rec_type(const char *string) { iot_rec_type *type_t = type_table; while (type_t->rec_string) { if (0 == strcmp(string, type_t->rec_string)) { return type_t->type; } type_t++; } return 0; } static int iot_device_rec_handle(const char *object) { json_object *json = NULL; json_object *result = NULL; char *type = NULL; int len = 0; char dh_key[32]; unsigned char dh_cli_key[32]; unsigned char dh_ap_key[32]; char dh_p[64]; char dh_g[12]; unsigned char rec_buf[64]; if (NULL == object) { log_info("Input is empty"); return -1; } json = json_tokener_parse(object); if (NULL == json) { log_info("Parsing error"); return -1; } type = (char *)json_object_get_string(json_object_object_get(json, "type")); switch (check_rec_type(type)) { case KEYNGREQ : log_info("%s\n", object); result = json_object_array_get_idx(json_object_object_get(json, "keymodelist"), 0); log_info("the keymode is :%s\n", json_object_get_string(json_object_object_get(result, "keymode"))); iot_device_local.protected = 0; iot_device_local.e_event = aplink_receive_keyngreq; break; case DH : log_info("DH"); log_info("%s\n", object); json_object_object_get_ex(json, "data", &result); log_info("dh_key : %s\n", json_object_get_string(json_object_object_get(result, "dh_key"))); strcpy((char *)iot_device_local.dh_p, json_object_get_string(json_object_object_get(result, "dh_p"))); strcpy((char *)iot_device_local.dh_g, json_object_get_string(json_object_object_get(result, "dh_g"))); log_info("dh_p : %s\n", iot_device_local.dh_p); log_info("dh_g : %s\n", iot_device_local.dh_g); len = dh_base64_decode(iot_device_local.dh_p, rec_buf); Hex2Str(rec_buf, dh_p, len); log_info("dh_p : %s", dh_p); len = dh_base64_decode((unsigned char *)iot_device_local.dh_g, rec_buf); Hex2Str(rec_buf, dh_g, len); log_info("dh_g : %s", dh_g); dh_calculate_public_key(&(iot_device_local.dhm_cli), dh_p, dh_g, dh_ap_key); dh_base64_encode(dh_ap_key, 16, iot_device_local.dh_key); log_info("public_key encode : %s", iot_device_local.dh_key); len = dh_base64_decode((unsigned char *)json_object_get_string(json_object_object_get(result, "dh_key")), dh_cli_key); calculate_common_key(&(iot_device_local.dhm_cli), dh_cli_key, (char *)iot_device_local.common_key); /* put_buf(iot_device_local.common_key, 16); */ iot_device_local.protected = 1; iot_device_local.e_event = aplink_receive_dh_info; os_time_dly(30); break; case QPLINK : log_info("QPLINK"); log_info("%s\n", object); if (0 != strcmp(json_object_get_string(json_object_object_get(json, "result")), "allow")) { log_info("Failed to obtain information"); break; } json_object_object_get_ex(json, "wifi", &result); strcpy(iot_device_local.ssid, json_object_get_string(json_object_object_get(result, "ssid"))); strcpy(iot_device_local.pwd, json_object_get_string(json_object_object_get(result, "password"))); log_info("ssid : %s\n", iot_device_local.ssid); log_info("password : %s\n", iot_device_local.pwd); iot_device_local.protected = 0; iot_device_local.e_event = aplink_receive_aplink_info; break; case ACK : log_info("ACK"); log_info("%s\n", object); iot_device_local.e_event = aplink_receive_ack; break; default: log_info("Data is not defined"); break; } json_object_put(json); return 0; } static int dh_p_base64_encode(const unsigned char *p, const int p_len, unsigned char *output) { int out_len; memcpy(output, base64_encode(p, p_len, &out_len), out_len); *(output + out_len) = '\0'; return out_len; } static int dh_base64_encode(const unsigned char *input, const int len, unsigned char *output) { int out_len; memcpy(output, base64_encode(input, len, &out_len), out_len); *(output + out_len) = '\0'; return out_len; } static int dh_g_base64_encode(const unsigned char *g, const int g_len, unsigned char *output) { int out_len; memcpy(output, base64_encode(g, g_len, &out_len), out_len); *(output + out_len) = '\0'; return out_len; } static int calculate_common_key(mbedtls_dhm_context *context, unsigned char *srv_pub, char *out_put) { unsigned char secret[16]; int ret; size_t n = 0; /* mbedtls_ctr_drbg_context ctr_drbg; */ mbedtls_ctr_drbg_init(&ctr_drbg); ret = mbedtls_dhm_read_public(context, srv_pub, 16); ret = mbedtls_dhm_calc_secret(context, secret, sizeof(secret), &n, mbedtls_ctr_drbg_random, &ctr_drbg); if (ret != 0) { mbedtls_printf(" failed\n! mbedtls_dhm_calc_secret %d\n", ret); return -1; } memcpy(out_put, secret, 16); mbedtls_dhm_free(context); mbedtls_ctr_drbg_free(&ctr_drbg); return 0; } static int dh_base64_decode(const unsigned char *input, unsigned char *output) { int out_len; memcpy(output, base64_decode(input, strlen((char *)input), &out_len), out_len); /* put_buf(output, out_len); */ return out_len; } static int aes_cbc_encode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *encode_buf) { unsigned char iv[16] = {0}; unsigned int encode_len; CT_AES_CBC_Encrypt(input_buf, input_len, key, 16, iv, 16, encode_buf, &encode_len); return encode_len; } static int aes_cbc_decode(unsigned char *input_buf, unsigned int input_len, unsigned char *key, unsigned char *decode_buf) { unsigned char iv[16] = {0}; unsigned int decode_len; CT_AES_CBC_Decrypt(input_buf, input_len, key, 16, iv, 16, decode_buf, &decode_len); return decode_len; } static int aqlink_package_assembly(char *data, int data_len, char *package, int package_buf_len) { if (data == NULL || data_len <= 0 || package == NULL || (data_len + 8) > package_buf_len) { return -1; } package[0] = 0x3f; package[1] = 0x72; package[2] = 0x1f; package[3] = 0xb5; package[4] = (u8)(((u32)data_len >> 24) & 0x00ff); package[5] = (u8)(((u32)data_len >> 16) & 0x00ff); package[6] = (u8)(((u32)data_len >> 8) & 0x00ff); package[7] = (u8)(((u32)data_len >> 0) & 0x00ff); memcpy(package + 8, data, data_len); return (data_len + 8); } const static int iot_device_send_keyngack(char *buf, int buf_len) { char temp_buf[512]; unsigned int len; char *keyngack = "{\"type\":\"keyngack\",\"sequence\":1,\"keymode\":\"dh\"}"; len = aqlink_package_assembly(keyngack, strlen(keyngack), buf, buf_len); return len; } const static int iot_device_send_dh(char *buf, int buf_len) { char temp_buf[256]; char key[64]; char dh_p[64]; char dh_g[64]; unsigned int len; snprintf(temp_buf, sizeof(temp_buf), DH_INFO, iot_device_local.dh_key, iot_device_local.dh_p, iot_device_local.dh_g); log_info("iot_device_send_dh : %s", temp_buf); len = aqlink_package_assembly(temp_buf, strlen(temp_buf), buf, buf_len); return len; } const static int iot_device_send_aplinkget(char *buf, int buf_len) { unsigned int len; unsigned char encode_buf[512]; int encode_len; char *aplinkget = "{\"type\":\"aplinkget\",\"sequence\":3,\"result\":\"get\"}"; encode_len = aes_cbc_encode((unsigned char *)aplinkget, strlen((char *)aplinkget), iot_device_local.common_key, encode_buf); len = aqlink_package_assembly((char *)encode_buf, encode_len, buf, buf_len); /* char decode_buf[256]; */ /* int decode_len; */ /* decode_len = aes_cbc_decode(encode_buf, encode_len, iot_device_local.common_key, decode_buf); */ /* decode_buf[decode_len] = '\0'; */ /* log_info("aplinkget decode: %s", decode_buf); */ return len; } void qlink_cfg_stop(void) { if (ap_elink_sock) { flag = 1; sock_set_quit(ap_elink_sock); while (flag) { os_time_dly(20); } sock_unreg(ap_elink_sock); ap_elink_sock = NULL; } }