Implement Regist Request

This commit is contained in:
Florian Märkl 2019-08-14 22:23:10 +02:00
commit 42cca4618f
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
7 changed files with 335 additions and 9 deletions

View file

@ -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}")

View 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

View file

@ -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
View 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(&regist->stop_pipe);
if(err != CHIAKI_ERR_SUCCESS)
goto error_psn_id;
err = chiaki_thread_create(&regist->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(&regist->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(&regist->thread, NULL);
chiaki_stop_pipe_fini(&regist->stop_pipe);
free(regist->info.host);
}
CHIAKI_EXPORT void chiaki_regist_stop(ChiakiRegist *regist)
{
chiaki_stop_pipe_stop(&regist->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;
}

View file

@ -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 };

View file

@ -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)
{