mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-14 18:57:07 -07:00
Implement Regist Request
This commit is contained in:
parent
a0476c1f51
commit
42cca4618f
7 changed files with 335 additions and 9 deletions
|
@ -31,7 +31,8 @@ set(HEADER_FILES
|
|||
include/chiaki/controller.h
|
||||
include/chiaki/takionsendbuffer.h
|
||||
include/chiaki/time.h
|
||||
include/chiaki/fec.h)
|
||||
include/chiaki/fec.h
|
||||
include/chiaki/regist.h)
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/common.c
|
||||
|
@ -65,7 +66,8 @@ set(SOURCE_FILES
|
|||
src/controller.c
|
||||
src/takionsendbuffer.c
|
||||
src/time.c
|
||||
src/fec)
|
||||
src/fec
|
||||
src/regist.c)
|
||||
|
||||
add_subdirectory(protobuf)
|
||||
include_directories("${NANOPB_SOURCE_DIR}")
|
||||
|
|
69
lib/include/chiaki/regist.h
Normal file
69
lib/include/chiaki/regist.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHIAKI_REGIST_H
|
||||
#define CHIAKI_REGIST_H
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "thread.h"
|
||||
#include "stoppipe.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct chiaki_regist_info_t
|
||||
{
|
||||
char *host;
|
||||
char *psn_id;
|
||||
uint32_t pin;
|
||||
} ChiakiRegistInfo;
|
||||
|
||||
typedef enum chiaki_regist_event_type_t {
|
||||
CHIAKI_REGIST_EVENT_TYPE_CONNECTED,
|
||||
CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED,
|
||||
CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS
|
||||
} ChiakiRegistEventType;
|
||||
|
||||
typedef struct chiaki_regist_event_t
|
||||
{
|
||||
ChiakiRegistEventType type;
|
||||
} ChiakiRegistEvent;
|
||||
|
||||
typedef void (*ChiakiRegistCb)(ChiakiRegistEvent *event, void *user);
|
||||
|
||||
typedef struct chiaki_regist_t
|
||||
{
|
||||
ChiakiLog *log;
|
||||
ChiakiRegistInfo info;
|
||||
ChiakiRegistCb cb;
|
||||
void *cb_user;
|
||||
|
||||
ChiakiThread thread;
|
||||
ChiakiStopPipe stop_pipe;
|
||||
} ChiakiRegist;
|
||||
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLog *log, ChiakiRegistInfo *info, ChiakiRegistCb cb, void *cb_user);
|
||||
CHIAKI_EXPORT void chiaki_regist_fini(ChiakiRegist *regist);
|
||||
CHIAKI_EXPORT void chiaki_regist_stop(ChiakiRegist *regist);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CHIAKI_REGIST_H
|
|
@ -36,8 +36,10 @@ typedef struct chiaki_rpcrypt_t
|
|||
} ChiakiRPCrypt;
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning);
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_aeropause(uint8_t *aeropause, const uint8_t *nonce);
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, const uint8_t *morning);
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init_auth(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, const uint8_t *morning);
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init_regist(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, uint32_t pin);
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, uint8_t *iv, uint64_t counter);
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_encrypt(ChiakiRPCrypt *rpcrypt, uint64_t counter, uint8_t *in, uint8_t *out, size_t sz);
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_decrypt(ChiakiRPCrypt *rpcrypt, uint64_t counter, uint8_t *in, uint8_t *out, size_t sz);
|
||||
|
|
228
lib/src/regist.c
Normal file
228
lib/src/regist.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include <chiaki/regist.h>
|
||||
#include <chiaki/rpcrypt.h>
|
||||
#include <chiaki/random.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <netdb.h>
|
||||
|
||||
#define REGIST_PORT 9295
|
||||
|
||||
static void *regist_thread_func(void *user);
|
||||
static int regist_connect(ChiakiRegist *regist);
|
||||
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_start(ChiakiRegist *regist, ChiakiLog *log, ChiakiRegistInfo *info, ChiakiRegistCb cb, void *cb_user)
|
||||
{
|
||||
regist->log = log;
|
||||
regist->info = *info;
|
||||
regist->info.host = strdup(regist->info.host);
|
||||
if(!regist->info.host)
|
||||
return CHIAKI_ERR_MEMORY;
|
||||
regist->info.psn_id = strdup(regist->info.psn_id);
|
||||
if(!regist->info.psn_id)
|
||||
goto error_host;
|
||||
|
||||
regist->cb = cb;
|
||||
regist->cb_user = cb_user;
|
||||
|
||||
ChiakiErrorCode err = chiaki_stop_pipe_init(®ist->stop_pipe);
|
||||
if(err != CHIAKI_ERR_SUCCESS)
|
||||
goto error_psn_id;
|
||||
|
||||
err = chiaki_thread_create(®ist->thread, regist_thread_func, regist);
|
||||
if(err != CHIAKI_ERR_SUCCESS)
|
||||
goto error_stop_pipe;
|
||||
|
||||
return CHIAKI_ERR_SUCCESS;
|
||||
|
||||
error_stop_pipe:
|
||||
chiaki_stop_pipe_fini(®ist->stop_pipe);
|
||||
error_psn_id:
|
||||
free(regist->info.psn_id);
|
||||
error_host:
|
||||
free(regist->info.host);
|
||||
return err;
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_regist_fini(ChiakiRegist *regist)
|
||||
{
|
||||
chiaki_thread_join(®ist->thread, NULL);
|
||||
chiaki_stop_pipe_fini(®ist->stop_pipe);
|
||||
free(regist->info.host);
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_regist_stop(ChiakiRegist *regist)
|
||||
{
|
||||
chiaki_stop_pipe_stop(®ist->stop_pipe);
|
||||
}
|
||||
|
||||
static void regist_event_simple(ChiakiRegist *regist, ChiakiRegistEventType type)
|
||||
{
|
||||
ChiakiRegistEvent event = { 0 };
|
||||
event.type = type;
|
||||
regist->cb(&event, regist->cb_user);
|
||||
}
|
||||
|
||||
static const char * const request_fmt =
|
||||
"POST /sce/rp/regist HTTP/1.1\r\n"
|
||||
"HOST: 10.0.2.15\r\n" // random lol
|
||||
"User-Agent: remoteplay Windows\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %llu\r\n\r\n";
|
||||
|
||||
static const char * const request_inner_fmt =
|
||||
"Client-Type: Windows\r\n"
|
||||
"Np-Online-Id: %s\r\n\r\n";
|
||||
|
||||
static void *regist_thread_func(void *user)
|
||||
{
|
||||
ChiakiRegist *regist = user;
|
||||
|
||||
uint8_t nonce[CHIAKI_KEY_BYTES];
|
||||
ChiakiErrorCode err = chiaki_random_bytes_crypt(nonce, sizeof(nonce));
|
||||
if(err != CHIAKI_ERR_SUCCESS)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to generate random nonce");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ChiakiRPCrypt crypt;
|
||||
chiaki_rpcrypt_init_regist(&crypt, nonce, regist->info.pin);
|
||||
|
||||
uint8_t payload[0x400];
|
||||
static const size_t inner_header_off = 0x1e0;
|
||||
memset(payload, 'A', inner_header_off);
|
||||
chiaki_rpcrypt_aeropause(payload + 0x11c, nonce);
|
||||
int inner_header_size = snprintf((char *)payload + inner_header_off, sizeof(payload) - inner_header_off, request_inner_fmt, regist->info.psn_id);
|
||||
if(inner_header_size >= sizeof(payload) - inner_header_off)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to format payload");
|
||||
goto fail;
|
||||
}
|
||||
chiaki_rpcrypt_encrypt(&crypt, 0, payload + inner_header_off, payload + inner_header_off, inner_header_size);
|
||||
size_t payload_size = inner_header_off + inner_header_size;
|
||||
|
||||
char request_header[0x100];
|
||||
int request_header_size = snprintf(request_header, sizeof(request_header), request_fmt, (unsigned long long)payload_size);
|
||||
if(request_header_size >= sizeof(request_header))
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to format request");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int sock = regist_connect(regist);
|
||||
if(sock < 0)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist eventually failed to connect");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int s = send(sock, request_header, request_header_size, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to send request header");
|
||||
goto fail_socket;
|
||||
}
|
||||
|
||||
s = send(s, payload, payload_size, 0);
|
||||
if(s < 0)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to send payload");
|
||||
goto fail_socket;
|
||||
}
|
||||
|
||||
char recv_buf[0x100];
|
||||
ssize_t received;
|
||||
rerecv:
|
||||
received = recv(sock, recv_buf, sizeof(recv_buf) - 1, 0);
|
||||
if(received < 0)
|
||||
CHIAKI_LOGE(regist->log, "Failed");
|
||||
else
|
||||
{
|
||||
chiaki_log_hexdump(regist->log, CHIAKI_LOG_DEBUG, (uint8_t *)recv_buf, received);
|
||||
goto rerecv;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
|
||||
regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_SUCCESS); // TODO: communicate params
|
||||
return NULL;
|
||||
|
||||
fail_socket:
|
||||
close(sock);
|
||||
fail:
|
||||
regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int regist_connect(ChiakiRegist *regist)
|
||||
{
|
||||
struct addrinfo *addrinfos;
|
||||
int r = getaddrinfo(regist->info.host, NULL, NULL, &addrinfos);
|
||||
if(r != 0)
|
||||
{
|
||||
CHIAKI_LOGE(regist->log, "Regist failed to getaddrinfo on %s", regist->info.host);
|
||||
regist_event_simple(regist, CHIAKI_REGIST_EVENT_TYPE_FINISHED_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sock = -1;
|
||||
for(struct addrinfo *ai=addrinfos; ai; ai=ai->ai_next)
|
||||
{
|
||||
if(ai->ai_protocol != IPPROTO_TCP)
|
||||
continue;
|
||||
|
||||
if(ai->ai_addr->sa_family != AF_INET) // TODO: support IPv6
|
||||
continue;
|
||||
|
||||
struct sockaddr *sa = malloc(ai->ai_addrlen);
|
||||
if(!sa)
|
||||
continue;
|
||||
memcpy(sa, ai->ai_addr, ai->ai_addrlen);
|
||||
|
||||
set_port(sa, htons(REGIST_PORT));
|
||||
|
||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if(sock < 0)
|
||||
{
|
||||
free(sa);
|
||||
continue;
|
||||
}
|
||||
r = connect(sock, sa, ai->ai_addrlen);
|
||||
if(r < 0)
|
||||
{
|
||||
int errsv = errno;
|
||||
CHIAKI_LOGE(regist->log, "Regist connect failed: %s", strerror(errsv));
|
||||
close(sock);
|
||||
sock = -1;
|
||||
free(sa);
|
||||
continue;
|
||||
}
|
||||
free(sa);
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(addrinfos);
|
||||
|
||||
return sock;
|
||||
}
|
|
@ -23,11 +23,11 @@
|
|||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static const uint8_t echo_b[] = { 0xe1, 0xec, 0x9c, 0x3a, 0xdd, 0xbd, 0x08, 0x85, 0xfc, 0x0e, 0x1d, 0x78, 0x90, 0x32, 0xc0, 0x04 };
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning)
|
||||
{
|
||||
static const uint8_t echo_a[] = { 0x01, 0x49, 0x87, 0x9b, 0x65, 0x39, 0x8b, 0x39, 0x4b, 0x3a, 0x8d, 0x48, 0xc3, 0x0a, 0xef, 0x51 };
|
||||
static const uint8_t echo_b[] = { 0xe1, 0xec, 0x9c, 0x3a, 0xdd, 0xbd, 0x08, 0x85, 0xfc, 0x0e, 0x1d, 0x78, 0x90, 0x32, 0xc0, 0x04 };
|
||||
|
||||
for(uint8_t i=0; i<CHIAKI_KEY_BYTES; i++)
|
||||
{
|
||||
|
@ -49,12 +49,34 @@ CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(uint8_t *bright, uint8_t *am
|
|||
}
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_aeropause(uint8_t *aeropause, const uint8_t *nonce)
|
||||
{
|
||||
for(size_t i=0; i<CHIAKI_KEY_BYTES; i++)
|
||||
{
|
||||
uint8_t v = nonce[i];
|
||||
v -= i;
|
||||
v -= 0x29;
|
||||
v ^= echo_b[i];
|
||||
aeropause[i] = v;
|
||||
}
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, const uint8_t *morning)
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init_auth(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, const uint8_t *morning)
|
||||
{
|
||||
chiaki_rpcrypt_bright_ambassador(rpcrypt->bright, rpcrypt->ambassador, nonce, morning);
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT void chiaki_rpcrypt_init_regist(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, uint32_t pin)
|
||||
{
|
||||
static const uint8_t regist_aes_key[CHIAKI_KEY_BYTES] = { 0x3f, 0x1c, 0xc4, 0xb6, 0xdc, 0xbb, 0x3e, 0xcc, 0x50, 0xba, 0xed, 0xef, 0x97, 0x34, 0xc7, 0xc9 };
|
||||
memcpy(rpcrypt->ambassador, nonce, sizeof(rpcrypt->ambassador));
|
||||
memcpy(rpcrypt->bright, regist_aes_key, sizeof(rpcrypt->bright));
|
||||
rpcrypt->bright[0] ^= (uint8_t)((pin >> 0x18) & 0xff);
|
||||
rpcrypt->bright[1] ^= (uint8_t)((pin >> 0x10) & 0xff);
|
||||
rpcrypt->bright[2] ^= (uint8_t)((pin >> 0x08) & 0xff);
|
||||
rpcrypt->bright[3] ^= (uint8_t)((pin >> 0x00) & 0xff);
|
||||
}
|
||||
|
||||
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, uint8_t *iv, uint64_t counter)
|
||||
{
|
||||
uint8_t hmac_key[] = { 0xac, 0x07, 0x88, 0x83, 0xc8, 0x3a, 0x1f, 0xe8, 0x11, 0x46, 0x3a, 0xf3, 0x9e, 0xe3, 0xe3, 0x77 };
|
||||
|
|
|
@ -287,7 +287,7 @@ static void *session_thread_func(void *arg)
|
|||
|
||||
CHIAKI_LOGI(session->log, "Session request successful");
|
||||
|
||||
chiaki_rpcrypt_init(&session->rpcrypt, session->nonce, session->connect_info.morning);
|
||||
chiaki_rpcrypt_init_auth(&session->rpcrypt, session->nonce, session->connect_info.morning);
|
||||
|
||||
// PS4 doesn't always react right away, sleep a bit
|
||||
chiaki_cond_timedwait_pred(&session->state_cond, &session->state_mutex, 10, session_check_state_pred, session);
|
||||
|
@ -482,7 +482,10 @@ static bool session_thread_request_session(ChiakiSession *session)
|
|||
|
||||
session_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if(session_sock < 0)
|
||||
{
|
||||
free(sa);
|
||||
continue;
|
||||
}
|
||||
r = connect(session_sock, sa, ai->ai_addrlen);
|
||||
if(r < 0)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue