diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index c6647bd..289fca4 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -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}")
diff --git a/lib/include/chiaki/ecdh.h b/lib/include/chiaki/ecdh.h
new file mode 100644
index 0000000..50162ad
--- /dev/null
+++ b/lib/include/chiaki/ecdh.h
@@ -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 .
+ */
+
+#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
diff --git a/lib/include/chiaki/launchspec.h b/lib/include/chiaki/launchspec.h
new file mode 100644
index 0000000..a23716c
--- /dev/null
+++ b/lib/include/chiaki/launchspec.h
@@ -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 .
+ */
+
+#ifndef CHIAKI_LAUNCHSPEC_H
+#define CHIAKI_LAUNCHSPEC_H
+
+#include "common.h"
+
+#include
+#include
+
+#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
diff --git a/lib/include/chiaki/random.h b/lib/include/chiaki/random.h
new file mode 100644
index 0000000..ee35f20
--- /dev/null
+++ b/lib/include/chiaki/random.h
@@ -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 .
+ */
+
+#ifndef CHIAKI_RANDOM_H
+#define CHIAKI_RANDOM_H
+
+#include "common.h"
+
+#include
+#include
+
+#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
diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h
index 1a85128..41dbaca 100644
--- a/lib/include/chiaki/session.h
+++ b/lib/include/chiaki/session.h
@@ -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;
diff --git a/lib/src/ecdh.c b/lib/src/ecdh.c
new file mode 100644
index 0000000..0cf366d
--- /dev/null
+++ b/lib/src/ecdh.c
@@ -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 .
+ */
+
+#include
+
+CHIAKI_EXPORT ChiakiErrorCode chiaki_ecdh_init(ChiakiECDH *ecdh)
+{
+ return CHIAKI_ERR_SUCCESS;
+}
+
+CHIAKI_EXPORT void chiaki_ecdh_fini(ChiakiECDH *ecdh)
+{
+
+}
\ No newline at end of file
diff --git a/lib/src/launchspec.c b/lib/src/launchspec.c
new file mode 100644
index 0000000..014fe58
--- /dev/null
+++ b/lib/src/launchspec.c
@@ -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 .
+ */
+
+#include
+#include
+#include
+
+#include
+
+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;
+}
\ No newline at end of file
diff --git a/lib/src/nagare.c b/lib/src/nagare.c
index a8c72ef..22b652f 100644
--- a/lib/src/nagare.c
+++ b/lib/src/nagare.c
@@ -18,6 +18,8 @@
#include
#include
+#include
+#include
#include
#include
@@ -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;
}
diff --git a/lib/src/random.c b/lib/src/random.c
new file mode 100644
index 0000000..18960c7
--- /dev/null
+++ b/lib/src/random.c
@@ -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 .
+ */
+
+#include
+
+#include
+
+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;
+}
\ No newline at end of file
diff --git a/lib/src/session.c b/lib/src/session.c
index dc96193..d3bf85e 100644
--- a/lib/src/session.c
+++ b/lib/src/session.c
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
@@ -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;
}
-
diff --git a/lib/src/utils.h b/lib/src/utils.h
index 6d4a191..b1e2ff0 100644
--- a/lib/src/utils.h
+++ b/lib/src/utils.h
@@ -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