LaunchSpec

This commit is contained in:
Florian Märkl 2018-11-24 21:51:59 +01:00
commit f86ecd931b
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
11 changed files with 359 additions and 9 deletions

View file

@ -11,7 +11,10 @@ set(HEADER_FILES
include/chiaki/takion.h
include/chiaki/senkusha.h
include/chiaki/nagare.h
include/chiaki/mirai.h)
include/chiaki/mirai.h
include/chiaki/ecdh.h
include/chiaki/launchspec.h
include/chiaki/random.h)
set(SOURCE_FILES
src/common.c
@ -27,7 +30,10 @@ set(SOURCE_FILES
src/utils.h
src/pb_utils.h
src/nagare.c
src/mirai.c)
src/mirai.c
src/ecdh.c
src/launchspec.c
src/random.c)
add_subdirectory(protobuf)
include_directories("${NANOPB_SOURCE_DIR}")

39
lib/include/chiaki/ecdh.h Normal file
View file

@ -0,0 +1,39 @@
/*
* 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_ECDH_H
#define CHIAKI_ECDH_H
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct chiaki_ecdh_t
{
} ChiakiECDH;
CHIAKI_EXPORT ChiakiErrorCode chiaki_ecdh_init(ChiakiECDH *ecdh);
CHIAKI_EXPORT void chiaki_ecdh_fini(ChiakiECDH *ecdh);
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_ECDH_H

View file

@ -0,0 +1,43 @@
/*
* 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_LAUNCHSPEC_H
#define CHIAKI_LAUNCHSPEC_H
#include "common.h"
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct chiaki_launch_spec_t
{
unsigned int mtu;
unsigned int rtt;
uint8_t *handshake_key;
} ChiakiLaunchSpec;
CHIAKI_EXPORT ssize_t chiaki_launchspec_format(char *buf, size_t buf_size, ChiakiLaunchSpec *launch_spec);
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_LAUNCHSPEC_H

View file

@ -0,0 +1,36 @@
/*
* 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_RANDOM_H
#define CHIAKI_RANDOM_H
#include "common.h"
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
CHIAKI_EXPORT ChiakiErrorCode chiaki_random_bytes(uint8_t *buf, size_t buf_size);
#ifdef __cplusplus
}
#endif
#endif // CHIAKI_RANDOM_H

View file

@ -36,6 +36,7 @@ extern "C" {
#define CHIAKI_RP_DID_SIZE 32
#define CHIAKI_SESSION_ID_SIZE_MAX 80
#define CHIAKI_HANDSHAKE_KEY_SIZE 0x10
typedef struct chiaki_connect_info_t
{
@ -96,7 +97,10 @@ typedef struct chiaki_session_t
uint8_t nonce[CHIAKI_KEY_BYTES];
ChiakiRPCrypt rpcrypt;
char session_id[CHIAKI_SESSION_ID_SIZE_MAX];
char session_id[CHIAKI_SESSION_ID_SIZE_MAX]; // zero-terminated
uint8_t handshake_key[CHIAKI_HANDSHAKE_KEY_SIZE];
unsigned int mtu;
unsigned int rtt;
ChiakiQuitReason quit_reason;

28
lib/src/ecdh.c Normal file
View file

@ -0,0 +1,28 @@
/*
* 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 <chiaki/ecdh.h>
CHIAKI_EXPORT ChiakiErrorCode chiaki_ecdh_init(ChiakiECDH *ecdh)
{
return CHIAKI_ERR_SUCCESS;
}
CHIAKI_EXPORT void chiaki_ecdh_fini(ChiakiECDH *ecdh)
{
}

90
lib/src/launchspec.c Normal file
View file

@ -0,0 +1,90 @@
/*
* 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 <chiaki/launchspec.h>
#include <chiaki/session.h>
#include <chiaki/base64.h>
#include <stdio.h>
static const char launchspec_fmt[] =
"{"
"\"sessionId\":\"sessionId4321\","
"\"streamResolutions\":["
"{"
"\"resolution\":"
"{"
"\"width\":640,"
"\"height\":360"
"},"
"\"maxFps\":30,"
"\"score\":10"
"}"
"],"
"\"network\":{"
"\"bwKbpsSent\":2000,"
"\"bwLoss\":0.001000,"
"\"mtu\":%u," // 0
"\"rtt\":%u," // 1
"\"ports\":[53,2053]"
"},"
"\"slotId\":1,"
"\"appSpecification\":{"
"\"minFps\":30,"
"\"minBandwidth\":0,"
"\"extTitleId\":\"ps3\","
"\"version\":1,"
"\"timeLimit\":1,"
"\"startTimeout\":100,"
"\"afkTimeout\":100,"
"\"afkTimeoutDisconnect\":100"
"},"
"\"konan\":{"
"\"ps3AccessToken\":\"accessToken\","
"\"ps3RefreshToken\":\"refreshToken\""
"},\"requestGameSpecification\":{"
"\"model\":\"bravia_tv\","
"\"platform\":\"android\","
"\"audioChannels\":\"5.1\","
"\"language\":\"sp\","
"\"acceptButton\":\"X\","
"\"connectedControllers\":[\"xinput\",\"ds3\",\"ds4\"],"
"\"yuvCoefficient\":\"bt601\","
"\"videoEncoderProfile\":\"hw4.1\","
"\"audioEncoderProfile\":\"audio1\""
"},"
"\"userProfile\":{"
"\"onlineId\":\"psnId\","
"\"npId\":\"npId\","
"\"region\":\"US\","
"\"languagesUsed\":[\"en\",\"jp\"]"
"},"
"\"handshakeKey\":\"%s\"" // 2
"}";
CHIAKI_EXPORT ssize_t chiaki_launchspec_format(char *buf, size_t buf_size, ChiakiLaunchSpec *launch_spec)
{
char handshake_key_b64[CHIAKI_HANDSHAKE_KEY_SIZE * 2];
ChiakiErrorCode err = chiaki_base64_encode(launch_spec->handshake_key, CHIAKI_HANDSHAKE_KEY_SIZE, handshake_key_b64, sizeof(handshake_key_b64));
if(err != CHIAKI_ERR_SUCCESS)
return -1;
int written = snprintf(buf, buf_size, launchspec_fmt, launch_spec->mtu, launch_spec->rtt, handshake_key_b64);
if(written < 0 || written >= buf_size)
return -1;
return written;
}

View file

@ -18,6 +18,8 @@
#include <chiaki/nagare.h>
#include <chiaki/session.h>
#include <chiaki/launchspec.h>
#include <chiaki/base64.h>
#include <string.h>
#include <assert.h>
@ -43,6 +45,7 @@ static ChiakiErrorCode nagare_send_disconnect(ChiakiNagare *nagare);
CHIAKI_EXPORT ChiakiErrorCode chiaki_nagare_run(ChiakiSession *session)
{
ChiakiNagare *nagare = &session->nagare;
nagare->session = session;
nagare->log = &session->log;
ChiakiErrorCode err = chiaki_mirai_init(&nagare->bang_mirai);
@ -144,20 +147,71 @@ static void nagare_takion_data(uint8_t *buf, size_t buf_size, void *user)
}
}
static bool chiaki_pb_encode_zero_encrypted_key(pb_ostream_t *stream, const pb_field_t *field, void *const *arg)
{
if (!pb_encode_tag_for_field(stream, field))
return false;
uint8_t data[] = { 0, 0, 0, 0 };
return pb_encode_string(stream, data, sizeof(data));
}
#define LAUNCH_SPEC_JSON_BUF_SIZE 1024
static ChiakiErrorCode nagare_send_big(ChiakiNagare *nagare)
{
ChiakiSession *session = nagare->session;
ChiakiLaunchSpec launch_spec;
launch_spec.mtu = session->mtu;
launch_spec.rtt = session->rtt;
launch_spec.handshake_key = session->handshake_key;
union
{
char json[LAUNCH_SPEC_JSON_BUF_SIZE];
char b64[LAUNCH_SPEC_JSON_BUF_SIZE * 2];
} launch_spec_buf;
ssize_t launch_spec_json_size = chiaki_launchspec_format(launch_spec_buf.json, sizeof(launch_spec_buf.json), &launch_spec);
if(launch_spec_json_size != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(nagare->log, "Nagare failed to format LaunchSpec json\n");
return CHIAKI_ERR_UNKNOWN;
}
launch_spec_json_size += 1; // we also want the trailing 0
uint8_t launch_spec_json_enc[LAUNCH_SPEC_JSON_BUF_SIZE];
memset(launch_spec_json_enc, 0, (size_t)launch_spec_json_size);
ChiakiErrorCode err = chiaki_rpcrypt_encrypt(&session->rpcrypt, 0, launch_spec_json_enc, launch_spec_json_enc,
(size_t)launch_spec_json_size);
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(nagare->log, "Nagare failed to encrypt LaunchSpec\n");
return err;
}
xor_bytes(launch_spec_json_enc, (uint8_t *)launch_spec_buf.json, (size_t)launch_spec_json_size);
err = chiaki_base64_encode(launch_spec_json_enc, (size_t)launch_spec_json_size, launch_spec_buf.b64, sizeof(launch_spec_buf.b64));
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(nagare->log, "Nagare failed to encode LaunchSpec as base64\n");
return err;
}
tkproto_TakionMessage msg;
memset(&msg, 0, sizeof(msg));
msg.type = tkproto_TakionMessage_PayloadType_BIG;
msg.has_big_payload = true;
msg.big_payload.client_version = 9;
msg.big_payload.session_key.arg = "";
msg.big_payload.session_key.arg = session->session_id;
msg.big_payload.session_key.funcs.encode = chiaki_pb_encode_string;
msg.big_payload.launch_spec.arg = "";
msg.big_payload.launch_spec.arg = launch_spec_buf.b64;
msg.big_payload.launch_spec.funcs.encode = chiaki_pb_encode_string;
msg.big_payload.encrypted_key.arg = "";
msg.big_payload.encrypted_key.funcs.encode = chiaki_pb_encode_string;
msg.big_payload.encrypted_key.funcs.encode = chiaki_pb_encode_zero_encrypted_key;
// TODO: msg.big_payload.ecdh_pub_key
// TODO: msg.big_payload.ecdh_sig
uint8_t buf[12];
size_t buf_size;
@ -171,7 +225,7 @@ static ChiakiErrorCode nagare_send_big(ChiakiNagare *nagare)
}
buf_size = stream.bytes_written;
ChiakiErrorCode err = chiaki_takion_send_message_data(&nagare->takion, 0, 1, 1, buf, buf_size);
err = chiaki_takion_send_message_data(&nagare->takion, 0, 1, 1, buf, buf_size);
return err;
}

28
lib/src/random.c Normal file
View file

@ -0,0 +1,28 @@
/*
* 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 <chiaki/random.h>
#include <openssl/rand.h>
CHIAKI_EXPORT ChiakiErrorCode chiaki_random_bytes(uint8_t *buf, size_t buf_size)
{
int r = RAND_bytes(buf, (int)buf_size);
if(!r)
return CHIAKI_ERR_UNKNOWN;
return CHIAKI_ERR_SUCCESS;
}

View file

@ -19,6 +19,7 @@
#include <chiaki/session.h>
#include <chiaki/http.h>
#include <chiaki/base64.h>
#include <chiaki/random.h>
#include <stdlib.h>
#include <string.h>
@ -163,8 +164,19 @@ static void *session_thread_func(void *arg)
goto quit_ctrl;
}
// TODO: Senkusha should set that
session->mtu = 1454;
session->rtt = 12;
CHIAKI_LOGI(&session->log, "Senkusha completed successfully\n");
err = chiaki_random_bytes(session->handshake_key, sizeof(session->handshake_key));
if(err != CHIAKI_ERR_SUCCESS)
{
CHIAKI_LOGE(&session->log, "Session failed to generate handshake key\n");
goto quit_ctrl;
}
err = chiaki_nagare_run(session);
if(err != CHIAKI_ERR_SUCCESS)
{
@ -375,4 +387,3 @@ static bool session_thread_request_session(ChiakiSession *session)
close(session_sock);
return response.success;
}

View file

@ -32,4 +32,15 @@ static inline ChiakiErrorCode set_port(struct sockaddr *sa, in_port_t port)
return CHIAKI_ERR_SUCCESS;
}
static inline void xor_bytes(uint8_t *dst, uint8_t *src, size_t sz)
{
while(sz > 0)
{
*dst ^= *src;
dst++;
src++;
sz--;
}
}
#endif // CHIAKI_UTILS_H