diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index c54b4af..dfb41bd 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -40,7 +40,9 @@ add_executable(chiaki include/settings.h src/settings.cpp include/registdialog.h - src/registdialog.cpp) + src/registdialog.cpp + include/host.h + src/host.cpp) target_include_directories(chiaki PRIVATE include) target_link_libraries(chiaki chiaki-lib chiaki-cli-lib) diff --git a/gui/include/host.h b/gui/include/host.h new file mode 100644 index 0000000..4abd3ae --- /dev/null +++ b/gui/include/host.h @@ -0,0 +1,61 @@ +/* + * This file is part of Chiaki. + * + * Chiaki is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chiaki is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chiaki. If not, see . + */ + +#ifndef CHIAKI_HOST_H +#define CHIAKI_HOST_H + +#include +#include + +#include + +class HostMAC +{ + private: + uint8_t mac[6]; + + public: + HostMAC() { memset(mac, 0, sizeof(mac)); } + explicit HostMAC(const uint8_t mac[6]) { memcpy(this->mac, mac, sizeof(this->mac)); } + const uint8_t *GetMAC() const { return mac; } +}; + +static bool operator==(const HostMAC &a, const HostMAC &b) { return memcmp(a.GetMAC(), b.GetMAC(), 6) == 0; } + +class RegisteredHost +{ + private: + QString ap_ssid; + QString ap_bssid; + QString ap_key; + QString ap_name; + HostMAC ps4_mac; + QString ps4_nickname; + char rp_regist_key[CHIAKI_SESSION_AUTH_SIZE]; + uint32_t rp_key_type; + uint8_t rp_key[0x10]; + + public: + RegisteredHost(); + RegisteredHost(const ChiakiRegisteredHost &chiaki_host); + + const QString &GetPS4Nickname() const { return ps4_nickname; } +}; + +Q_DECLARE_METATYPE(RegisteredHost) + +#endif //CHIAKI_HOST_H diff --git a/gui/include/registdialog.h b/gui/include/registdialog.h index b31a95c..3f10235 100644 --- a/gui/include/registdialog.h +++ b/gui/include/registdialog.h @@ -18,6 +18,8 @@ #ifndef CHIAKI_REGISTDIALOG_H #define CHIAKI_REGISTDIALOG_H +#include "host.h" + #include #include @@ -69,7 +71,7 @@ class RegistExecuteDialog: public QDialog private slots: void Log(ChiakiLogLevel level, QString msg); - void Success(); + void Success(RegisteredHost host); void Failed(); public: diff --git a/gui/src/host.cpp b/gui/src/host.cpp new file mode 100644 index 0000000..141bb9a --- /dev/null +++ b/gui/src/host.cpp @@ -0,0 +1,37 @@ +/* + * This file is part of Chiaki. + * + * Chiaki is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Chiaki is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chiaki. If not, see . + */ + +#include + +RegisteredHost::RegisteredHost() +{ + memset(rp_regist_key, 0, sizeof(rp_regist_key)); + memset(rp_key, 0, sizeof(rp_key)); +} + +RegisteredHost::RegisteredHost(const ChiakiRegisteredHost &chiaki_host) + : ps4_mac(chiaki_host.ps4_mac) +{ + ap_ssid = chiaki_host.ap_ssid; + ap_bssid = chiaki_host.ap_bssid; + ap_key = chiaki_host.ap_key; + ap_name = chiaki_host.ap_name; + ps4_nickname = chiaki_host.ps4_nickname; + memcpy(rp_regist_key, chiaki_host.rp_regist_key, sizeof(rp_regist_key)); + rp_key_type = chiaki_host.rp_key_type; + memcpy(rp_key, chiaki_host.rp_key, sizeof(rp_key)); +} \ No newline at end of file diff --git a/gui/src/main.cpp b/gui/src/main.cpp index 2e31bd4..0a7496b 100644 --- a/gui/src/main.cpp +++ b/gui/src/main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -38,6 +39,7 @@ int RunMain(QApplication &app, Settings *settings); int main(int argc, char *argv[]) { qRegisterMetaType(); + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); diff --git a/gui/src/registdialog.cpp b/gui/src/registdialog.cpp index ae549d6..f1d23be 100644 --- a/gui/src/registdialog.cpp +++ b/gui/src/registdialog.cpp @@ -141,9 +141,9 @@ void RegistExecuteDialog::Finished() button_box->addButton(QDialogButtonBox::Close); } -void RegistExecuteDialog::Success() +void RegistExecuteDialog::Success(RegisteredHost host) { - printf("finished\n"); + CHIAKI_LOGI(&log, "Successfully registered %s", host.GetPS4Nickname().toLocal8Bit().constData()); Finished(); } @@ -164,7 +164,7 @@ class RegistExecuteDialogPrivate switch(event->type) { case CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS: - QMetaObject::invokeMethod(dialog, "Success", Qt::ConnectionType::QueuedConnection); + QMetaObject::invokeMethod(dialog, "Success", Qt::ConnectionType::QueuedConnection, Q_ARG(RegisteredHost, *event->registered_host)); break; case CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED: QMetaObject::invokeMethod(dialog, "Failed", Qt::ConnectionType::QueuedConnection); diff --git a/lib/include/chiaki/regist.h b/lib/include/chiaki/regist.h index 1c821b2..5351625 100644 --- a/lib/include/chiaki/regist.h +++ b/lib/include/chiaki/regist.h @@ -23,6 +23,7 @@ #include "thread.h" #include "stoppipe.h" #include "rpcrypt.h" +#include "session.h" #ifdef __cplusplus extern "C" { @@ -35,6 +36,19 @@ typedef struct chiaki_regist_info_t uint32_t pin; } ChiakiRegistInfo; +typedef struct chiaki_registered_host_t +{ + char ap_ssid[0x30]; + char ap_bssid[0x20]; + char ap_key[0x50]; + char ap_name[0x20]; + uint8_t ps4_mac[6]; + char ps4_nickname[0x20]; + char rp_regist_key[CHIAKI_SESSION_AUTH_SIZE]; // must be completely filled (pad with \0) + uint32_t rp_key_type; + uint8_t rp_key[0x10]; +} ChiakiRegisteredHost; + typedef enum chiaki_regist_event_type_t { CHIAKI_REGIST_EVENT_TYPE_CONNECTED, CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED, @@ -45,6 +59,7 @@ typedef enum chiaki_regist_event_type_t { typedef struct chiaki_regist_event_t { ChiakiRegistEventType type; + ChiakiRegisteredHost *registered_host; } ChiakiRegistEvent; typedef void (*ChiakiRegistCb)(ChiakiRegistEvent *event, void *user); diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index f096e58..5292630 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -65,12 +65,14 @@ typedef enum { CHIAKI_EXPORT void chiaki_connect_video_profile_preset(ChiakiConnectVideoProfile *profile, ChiakiVideoResolutionPreset resolution, ChiakiVideoFPSPreset fps); +#define CHIAKI_SESSION_AUTH_SIZE 0x10 + typedef struct chiaki_connect_info_t { const char *host; // null terminated const char *regist_key; // null terminated const char *ostype; // null terminated - char auth[0x10]; // must be completely filled (pad with \0) + char auth[CHIAKI_SESSION_AUTH_SIZE]; // must be completely filled (pad with \0) uint8_t morning[0x10]; uint8_t did[CHIAKI_RP_DID_SIZE]; ChiakiConnectVideoProfile video_profile; diff --git a/lib/src/discovery.c b/lib/src/discovery.c index 6ffa6c1..0f84faf 100644 --- a/lib/src/discovery.c +++ b/lib/src/discovery.c @@ -258,7 +258,7 @@ static void *discovery_thread_func(void *user) buf[n] = '\00'; - CHIAKI_LOGV(discovery->log, "Discovery received:\n%s", buf); + //CHIAKI_LOGV(discovery->log, "Discovery received:\n%s", buf); //chiaki_log_hexdump_raw(discovery->log, CHIAKI_LOG_VERBOSE, (const uint8_t *)buf, n); char addr_buf[64]; diff --git a/lib/src/regist.c b/lib/src/regist.c index 2a4b0bf..5ade981 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -36,7 +36,8 @@ static void *regist_thread_func(void *user); static ChiakiErrorCode regist_search(ChiakiRegist *regist, struct addrinfo *addrinfos); static int regist_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, int protocol); -static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, int sock, ChiakiRPCrypt *rpcrypt); +static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, ChiakiRegisteredHost *host, int sock, ChiakiRPCrypt *rpcrypt); +static ChiakiErrorCode regist_parse_response_payload(ChiakiRegist *regist, ChiakiRegisteredHost *host, char *buf, size_t buf_size); CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLog *log, const ChiakiRegistInfo *info, ChiakiRegistCb cb, void *cb_user) { @@ -200,7 +201,8 @@ static void *regist_thread_func(void *user) CHIAKI_LOGI(regist->log, "Regist waiting for response"); - err = regist_recv_response(regist, sock, &crypt); + ChiakiRegisteredHost host; + err = regist_recv_response(regist, &host, sock, &crypt); if(err != CHIAKI_ERR_SUCCESS) { CHIAKI_LOGE(regist->log, "Regist eventually failed"); @@ -210,7 +212,6 @@ static void *regist_thread_func(void *user) CHIAKI_LOGI(regist->log, "Regist successfully received response"); success = true; - // TODO: params fail_socket: close(sock); @@ -220,7 +221,12 @@ fail: if(canceled) regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_CANCELED); else if(success) - regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS); + { + ChiakiRegistEvent event = { 0 }; + event.type = CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS; + event.registered_host = &host; + regist->cb(&event, regist->cb_user); + } else regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED); return NULL; @@ -320,7 +326,7 @@ static int regist_connect(ChiakiRegist *regist, struct addrinfo *addrinfos, int return sock; } -static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, int sock, ChiakiRPCrypt *rpcrypt) +static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, ChiakiRegisteredHost *host, int sock, ChiakiRPCrypt *rpcrypt) { uint8_t buf[0x200]; size_t buf_filled_size; @@ -394,7 +400,126 @@ static ChiakiErrorCode regist_recv_response(ChiakiRegist *regist, int sock, Chia CHIAKI_LOGI(regist->log, "Regist response payload (decrypted):"); chiaki_log_hexdump(regist->log, CHIAKI_LOG_VERBOSE, payload, payload_size); - // TODO: parse content + err = regist_parse_response_payload(regist, host, (char *)payload, payload_size); + if(err != CHIAKI_ERR_SUCCESS) + { + CHIAKI_LOGE(regist->log, "Regist failed to parse response payload"); + return err; + } + + return CHIAKI_ERR_SUCCESS; +} + +static ChiakiErrorCode regist_parse_response_payload(ChiakiRegist *regist, ChiakiRegisteredHost *host, char *buf, size_t buf_size) +{ + ChiakiHttpHeader *headers; + ChiakiErrorCode err = chiaki_http_header_parse(&headers, buf, buf_size); + if(err != CHIAKI_ERR_SUCCESS) + { + CHIAKI_LOGE(regist->log, "Regist failed to parse response payload HTTP header"); + return err; + } + + memset(host, 0, sizeof(*host)); + + bool mac_found = false; + bool regist_key_found = false; + bool key_found = false; + + for(ChiakiHttpHeader *header=headers; header; header=header->next) + { +#define COPY_STRING(name, key_str) \ + if(strcmp(header->key, key_str) == 0) \ + { \ + size_t len = strlen(header->value); \ + if(len >= sizeof(host->name)) \ + { \ + CHIAKI_LOGE(regist->log, "Regist value for " key_str " in response is too long"); \ + continue; \ + } \ + memcpy(host->name, header->value, len); \ + host->name[len] = 0; \ + continue; \ + } + COPY_STRING(ap_ssid, "AP-Ssid") + COPY_STRING(ap_bssid, "AP-Bssid") + COPY_STRING(ap_key, "AP-Key") + COPY_STRING(ap_name, "AP-Name") + COPY_STRING(ps4_nickname, "PS4-Nickname") +#undef COPY_STRING + + if(strcmp(header->key, "PS4-RegistKey") == 0) + { + memset(host->rp_regist_key, 0, sizeof(host->rp_regist_key)); + size_t buf_size = sizeof(host->rp_regist_key); + err = parse_hex((uint8_t *)host->rp_regist_key, &buf_size, header->value, strlen(header->value)); + if(err != CHIAKI_ERR_SUCCESS) + { + CHIAKI_LOGE(regist->log, "Regist received invalid RegistKey in response"); + memset(host->rp_regist_key, 0, sizeof(host->rp_regist_key)); + } + else + { + regist_key_found = true; + } + } + else if(strcmp(header->key, "RP-KeyType") == 0) + { + host->rp_key_type = (uint32_t)strtoul(header->value, NULL, 0); + } + else if(strcmp(header->key, "RP-Key") == 0) + { + size_t buf_size = sizeof(host->rp_key); + err = parse_hex((uint8_t *)host->rp_key, &buf_size, header->value, strlen(header->value)); + if(err != CHIAKI_ERR_SUCCESS || buf_size != sizeof(host->rp_key)) + { + CHIAKI_LOGE(regist->log, "Regist received invalid key in response"); + memset(host->rp_key, 0, sizeof(host->rp_key)); + } + else + { + key_found = true; + } + } + else if(strcmp(header->key, "PS4-Mac") == 0) + { + size_t buf_size = sizeof(host->ps4_mac); + err = parse_hex((uint8_t *)host->ps4_mac, &buf_size, header->value, strlen(header->value)); + if(err != CHIAKI_ERR_SUCCESS || buf_size != sizeof(host->ps4_mac)) + { + CHIAKI_LOGE(regist->log, "Regist received invalid MAC Address in response"); + memset(host->ps4_mac, 0, sizeof(host->ps4_mac)); + } + else + { + mac_found = true; + } + } + else + { + CHIAKI_LOGI(regist->log, "Regist received unknown key %s in response payload", header->key); + } + } + + chiaki_http_header_free(headers); + + if(!regist_key_found) + { + CHIAKI_LOGE(regist->log, "Regist response is missing RegistKey (or it was invalid)"); + return CHIAKI_ERR_INVALID_RESPONSE; + } + + if(!key_found) + { + CHIAKI_LOGE(regist->log, "Regist response is missing key (or it was invalid)"); + return CHIAKI_ERR_INVALID_RESPONSE; + } + + if(!mac_found) + { + CHIAKI_LOGE(regist->log, "Regist response is missing MAC Adress (or it was invalid)"); + return CHIAKI_ERR_INVALID_RESPONSE; + } return CHIAKI_ERR_SUCCESS; } diff --git a/lib/src/utils.h b/lib/src/utils.h index b1e2ff0..9fd4deb 100644 --- a/lib/src/utils.h +++ b/lib/src/utils.h @@ -43,4 +43,37 @@ static inline void xor_bytes(uint8_t *dst, uint8_t *src, size_t sz) } } +static inline int8_t nibble_value(char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 0xa; + if(c >= 'A' && c <= 'F') + return c - 'A' + 0xa; + return -1; +} + +static inline ChiakiErrorCode parse_hex(uint8_t *buf, size_t *buf_size, const char *hex, size_t hex_size) +{ + if(hex_size % 2 != 0) + return CHIAKI_ERR_INVALID_DATA; + if(hex_size / 2 > *buf_size) + return CHIAKI_ERR_BUF_TOO_SMALL; + + for(size_t i=0; i