From 4dac2253df4b7e4d23658a35817158ecfcc76764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 16 Oct 2020 11:01:00 +0200 Subject: [PATCH] PS4 Firmware 8.0 Compatibility (Fix #328) --- .gitignore | 1 + android/app/build.gradle | 1 + android/app/src/main/cpp/chiaki-jni.c | 6 + .../java/com/metallic/chiaki/lib/Chiaki.kt | 9 + .../metallic/chiaki/regist/RegistActivity.kt | 24 +- .../metallic/chiaki/regist/RegistViewModel.kt | 3 +- .../src/main/res/layout/activity_regist.xml | 13 +- android/app/src/main/res/values/strings.xml | 3 +- gui/include/registdialog.h | 7 +- gui/src/registdialog.cpp | 49 +- lib/include/chiaki/common.h | 9 + lib/include/chiaki/regist.h | 3 +- lib/include/chiaki/rpcrypt.h | 11 +- lib/include/chiaki/session.h | 14 +- lib/src/ctrl.c | 32 +- lib/src/regist.c | 69 +- lib/src/rpcrypt.c | 937 +++++++++++++++++- lib/src/session.c | 70 +- test/regist.c | 27 +- test/rpcrypt.c | 121 ++- 20 files changed, 1273 insertions(+), 136 deletions(-) diff --git a/.gitignore b/.gitignore index 5e82c02..bb63e63 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ secret.tar keystore-env.sh compile_commands.json .ccls-cache +.gdb_history diff --git a/android/app/build.gradle b/android/app/build.gradle index a83e35a..62e5984 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -31,6 +31,7 @@ android { arguments "-DCHIAKI_ENABLE_TESTS=OFF", "-DCHIAKI_ENABLE_CLI=OFF", "-DCHIAKI_ENABLE_GUI=OFF", + "-DCHIAKI_ENABLE_SETSU=OFF", "-DCHIAKI_ENABLE_ANDROID=ON", "-DCHIAKI_LIB_ENABLE_OPUS=OFF", "-DCHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT=ON" diff --git a/android/app/src/main/cpp/chiaki-jni.c b/android/app/src/main/cpp/chiaki-jni.c index e0884ce..feab1a9 100644 --- a/android/app/src/main/cpp/chiaki-jni.c +++ b/android/app/src/main/cpp/chiaki-jni.c @@ -702,6 +702,11 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re ")V"); jclass regist_info_class = E->GetObjectClass(env, regist_info_obj); + + jobject target_obj = E->GetObjectField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "target", "L"BASE_PACKAGE"/Target;")); + jclass target_class = E->GetObjectClass(env, target_obj); + jint target_value = E->GetIntField(env, target_obj, E->GetFieldID(env, target_class, "value", "I")); + jstring host_string = E->GetObjectField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "host", "Ljava/lang/String;")); jboolean broadcast = E->GetBooleanField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "broadcast", "Z")); jstring psn_online_id_string = E->GetObjectField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "psnOnlineId", "Ljava/lang/String;")); @@ -709,6 +714,7 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re jint pin = E->GetIntField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "pin", "I")); ChiakiRegistInfo regist_info = { 0 }; + regist_info.target = (ChiakiTarget)target_value; regist_info.host = E->GetStringUTFChars(env, host_string, NULL); regist_info.broadcast = broadcast; if(psn_online_id_string) diff --git a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt index e511e22..bda96ac 100644 --- a/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt +++ b/android/app/src/main/java/com/metallic/chiaki/lib/Chiaki.kt @@ -3,11 +3,19 @@ package com.metallic.chiaki.lib import android.os.Parcelable import android.util.Log import android.view.Surface +import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize import java.lang.Exception import java.net.InetSocketAddress import kotlin.math.abs +enum class Target(val value: Int) +{ + PS4_8(800), + PS4_9(900), + PS4_10(1000) +} + enum class VideoResolutionPreset(val value: Int) { RES_360P(1), @@ -316,6 +324,7 @@ class DiscoveryService( @Parcelize data class RegistInfo( + val target: Target, val host: String, val broadcast: Boolean, val psnOnlineId: String?, diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt index 04e29f0..6be03f9 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistActivity.kt @@ -28,6 +28,7 @@ import androidx.lifecycle.ViewModelProvider import com.metallic.chiaki.R import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.lib.RegistInfo +import com.metallic.chiaki.lib.Target import kotlinx.android.synthetic.main.activity_regist.* import java.lang.IllegalArgumentException @@ -63,7 +64,8 @@ class RegistActivity: AppCompatActivity(), RevealActivity registButton.setOnClickListener { doRegist() } - ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.PS4Version.GE_7) { + ps4VersionRadioGroup.check(when(viewModel.ps4Version.value ?: RegistViewModel.PS4Version.GE_8) { + RegistViewModel.PS4Version.GE_8 -> R.id.ps4VersionGE8RadioButton RegistViewModel.PS4Version.GE_7 -> R.id.ps4VersionGE7RadioButton RegistViewModel.PS4Version.LT_7 -> R.id.ps4VersionLT7RadioButton }) @@ -71,6 +73,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> viewModel.ps4Version.value = when(checkedId) { + R.id.ps4VersionGE8RadioButton -> RegistViewModel.PS4Version.GE_8 R.id.ps4VersionGE7RadioButton -> RegistViewModel.PS4Version.GE_7 R.id.ps4VersionLT7RadioButton -> RegistViewModel.PS4Version.LT_7 else -> RegistViewModel.PS4Version.GE_7 @@ -78,11 +81,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity } viewModel.ps4Version.observe(this, Observer { - psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.PS4Version.GE_7) View.VISIBLE else View.GONE + psnAccountIdHelpGroup.visibility = if(it == RegistViewModel.PS4Version.LT_7) View.GONE else View.VISIBLE psnIdTextInputLayout.hint = getString(when(it!!) { - RegistViewModel.PS4Version.GE_7 -> R.string.hint_regist_psn_account_id RegistViewModel.PS4Version.LT_7 -> R.string.hint_regist_psn_online_id + else -> R.string.hint_regist_psn_account_id }) }) } @@ -98,14 +101,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity val psnId = psnIdEditText.text.toString().trim() val psnOnlineId: String? = if(ps4Version == RegistViewModel.PS4Version.LT_7) psnId else null val psnAccountId: ByteArray? = - if(ps4Version == RegistViewModel.PS4Version.GE_7) + if(ps4Version != RegistViewModel.PS4Version.LT_7) try { Base64.decode(psnId, Base64.DEFAULT) } catch(e: IllegalArgumentException) { null } else null val psnIdValid = when(ps4Version) { - RegistViewModel.PS4Version.GE_7 -> psnAccountId != null && psnAccountId.size == RegistInfo.ACCOUNT_ID_SIZE RegistViewModel.PS4Version.LT_7 -> psnOnlineId?.isNotEmpty() ?: false + else -> psnAccountId != null && psnAccountId.size == RegistInfo.ACCOUNT_ID_SIZE } @@ -117,8 +120,8 @@ class RegistActivity: AppCompatActivity(), RevealActivity if(!psnIdValid) getString(when(ps4Version) { - RegistViewModel.PS4Version.GE_7 -> R.string.regist_psn_account_id_invalid RegistViewModel.PS4Version.LT_7 -> R.string.regist_psn_online_id_invalid + else -> R.string.regist_psn_account_id_invalid }) else null @@ -127,7 +130,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity if(!hostValid || !psnIdValid || !pinValid) return - val registInfo = RegistInfo(host, broadcast, psnOnlineId, psnAccountId, pin.toInt()) + val target = when(ps4Version) + { + RegistViewModel.PS4Version.GE_8 -> Target.PS4_10 + RegistViewModel.PS4Version.GE_7 -> Target.PS4_9 + RegistViewModel.PS4Version.LT_7 -> Target.PS4_8 + } + + val registInfo = RegistInfo(target, host, broadcast, psnOnlineId, psnAccountId, pin.toInt()) Intent(this, RegistExecuteActivity::class.java).also { it.putExtra(RegistExecuteActivity.EXTRA_REGIST_INFO, registInfo) diff --git a/android/app/src/main/java/com/metallic/chiaki/regist/RegistViewModel.kt b/android/app/src/main/java/com/metallic/chiaki/regist/RegistViewModel.kt index 873008e..bc14037 100644 --- a/android/app/src/main/java/com/metallic/chiaki/regist/RegistViewModel.kt +++ b/android/app/src/main/java/com/metallic/chiaki/regist/RegistViewModel.kt @@ -23,9 +23,10 @@ import androidx.lifecycle.ViewModel class RegistViewModel: ViewModel() { enum class PS4Version { + GE_8, GE_7, LT_7 } - val ps4Version = MutableLiveData(PS4Version.GE_7) + val ps4Version = MutableLiveData(PS4Version.GE_8) } \ No newline at end of file diff --git a/android/app/src/main/res/layout/activity_regist.xml b/android/app/src/main/res/layout/activity_regist.xml index fff5cad..e174bb0 100644 --- a/android/app/src/main/res/layout/activity_regist.xml +++ b/android/app/src/main/res/layout/activity_regist.xml @@ -69,13 +69,22 @@ android:orientation="horizontal" app:layout_constraintTop_toBottomOf="@id/broadcastCheckBox"> + + + android:checked="false" + android:text="@string/regist_option_ps4_ge_7" /> + Host Broadcast PS4 < 7.0 - PS4 ≥ 7.0 + PS4 ≥ 7.0, < 8 + PS4 ≥ 8.0 About obtaining your Account ID, see https://github.com/thestr4ng3r/chiaki/blob/master/README.md#obtaining-your-psn-accountid PSN Online ID (username, case-sensitive) diff --git a/gui/include/registdialog.h b/gui/include/registdialog.h index d159960..fc01ca2 100644 --- a/gui/include/registdialog.h +++ b/gui/include/registdialog.h @@ -41,9 +41,10 @@ class RegistDialog : public QDialog QLineEdit *host_edit; QCheckBox *broadcast_check_box; - QRadioButton *psn_online_id_radio_button; + QRadioButton *ps4_pre9_radio_button; + QRadioButton *ps4_pre10_radio_button; + QRadioButton *ps4_10_radio_button; QLineEdit *psn_online_id_edit; - QRadioButton *psn_account_id_radio_button; QLineEdit *psn_account_id_edit; QLineEdit *pin_edit; QDialogButtonBox *button_box; @@ -51,6 +52,8 @@ class RegistDialog : public QDialog RegisteredHost registered_host; + bool NeedAccountId(); + private slots: void ValidateInput(); diff --git a/gui/src/registdialog.cpp b/gui/src/registdialog.cpp index 07e0844..0adcbbb 100644 --- a/gui/src/registdialog.cpp +++ b/gui/src/registdialog.cpp @@ -59,20 +59,29 @@ RegistDialog::RegistDialog(Settings *settings, const QString &host, QWidget *par broadcast_check_box->setChecked(host.isEmpty()); auto UpdatePSNIDEdits = [this]() { - psn_online_id_edit->setEnabled(psn_online_id_radio_button->isChecked()); - psn_account_id_edit->setEnabled(psn_account_id_radio_button->isChecked()); + bool need_account_id = NeedAccountId(); + psn_online_id_edit->setEnabled(!need_account_id); + psn_account_id_edit->setEnabled(need_account_id); }; - psn_online_id_radio_button = new QRadioButton(tr("PSN Online-ID (username, case-sensitive) for PS4 < 7.0:"), this); - psn_online_id_edit = new QLineEdit(this); - form_layout->addRow(psn_online_id_radio_button, psn_online_id_edit); - connect(psn_online_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + auto version_layout = new QVBoxLayout(nullptr); + ps4_pre9_radio_button = new QRadioButton(tr("< 7.0"), this); + version_layout->addWidget(ps4_pre9_radio_button); + connect(ps4_pre9_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + ps4_pre10_radio_button = new QRadioButton(tr(">= 7.0, < 8.0"), this); + version_layout->addWidget(ps4_pre10_radio_button); + connect(ps4_pre10_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + ps4_10_radio_button = new QRadioButton(tr(">= 8.0"), this); + version_layout->addWidget(ps4_10_radio_button); + connect(ps4_10_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + form_layout->addRow(tr("PS4 Firmware:"), version_layout); - psn_account_id_radio_button = new QRadioButton(tr("PSN Account-ID (base64) for PS4 >= 7.0:"), this); + psn_online_id_edit = new QLineEdit(this); + form_layout->addRow(tr("PSN Online-ID (username, case-sensitive):"), psn_online_id_edit); psn_account_id_edit = new QLineEdit(this); - form_layout->addRow(psn_account_id_radio_button, psn_account_id_edit); - psn_account_id_radio_button->setChecked(true); - connect(psn_account_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); + form_layout->addRow(tr("PSN Account-ID (base64):"), psn_account_id_edit); + + ps4_10_radio_button->setChecked(true); UpdatePSNIDEdits(); @@ -96,11 +105,17 @@ RegistDialog::~RegistDialog() { } +bool RegistDialog::NeedAccountId() +{ + return !ps4_pre9_radio_button->isChecked(); +} + void RegistDialog::ValidateInput() { + bool need_account_id = NeedAccountId(); bool valid = !host_edit->text().trimmed().isEmpty() - && (!psn_online_id_radio_button->isChecked() || !psn_online_id_edit->text().trimmed().isEmpty()) - && (!psn_account_id_radio_button->isChecked() || !psn_account_id_radio_button->text().trimmed().isEmpty()) + && !(!need_account_id && psn_online_id_edit->text().trimmed().isEmpty()) + && !(need_account_id && psn_account_id_edit->text().trimmed().isEmpty()) && pin_edit->text().length() == PIN_LENGTH; register_button->setEnabled(valid); } @@ -111,8 +126,16 @@ void RegistDialog::accept() QByteArray host = host_edit->text().trimmed().toUtf8(); info.host = host.constData(); + if(ps4_pre9_radio_button->isChecked()) + info.target = CHIAKI_TARGET_PS4_8; + else if(ps4_pre10_radio_button->isChecked()) + info.target = CHIAKI_TARGET_PS4_9; + else + info.target = CHIAKI_TARGET_PS4_10; + + bool need_account_id = NeedAccountId(); QByteArray psn_id; // keep this out of the if scope - if(psn_online_id_radio_button->isChecked()) + if(!need_account_id) { psn_id = psn_online_id_edit->text().trimmed().toUtf8(); info.psn_online_id = psn_id.constData(); diff --git a/lib/include/chiaki/common.h b/lib/include/chiaki/common.h index a2e87a4..484604e 100644 --- a/lib/include/chiaki/common.h +++ b/lib/include/chiaki/common.h @@ -72,6 +72,15 @@ CHIAKI_EXPORT const char *chiaki_error_string(ChiakiErrorCode code); CHIAKI_EXPORT void *chiaki_aligned_alloc(size_t alignment, size_t size); CHIAKI_EXPORT void chiaki_aligned_free(void *ptr); +typedef enum +{ + // values must not change + CHIAKI_TARGET_PS4_UNKNOWN = 0, + CHIAKI_TARGET_PS4_8 = 800, + CHIAKI_TARGET_PS4_9 = 900, + CHIAKI_TARGET_PS4_10 = 1000 +} ChiakiTarget; + /** * Perform initialization of global state needed for using the Chiaki lib */ diff --git a/lib/include/chiaki/regist.h b/lib/include/chiaki/regist.h index 6140967..d78b1ef 100644 --- a/lib/include/chiaki/regist.h +++ b/lib/include/chiaki/regist.h @@ -33,6 +33,7 @@ extern "C" { typedef struct chiaki_regist_info_t { + ChiakiTarget target; const char *host; bool broadcast; @@ -94,7 +95,7 @@ CHIAKI_EXPORT void chiaki_regist_stop(ChiakiRegist *regist); /** * @param psn_account_id must be exactly of size CHIAKI_PSN_ACCOUNT_ID_SIZE */ -CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id); +CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(ChiakiTarget target, const uint8_t *ambassador, uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id, uint32_t pin); #ifdef __cplusplus } diff --git a/lib/include/chiaki/rpcrypt.h b/lib/include/chiaki/rpcrypt.h index 12d0705..ef30abc 100644 --- a/lib/include/chiaki/rpcrypt.h +++ b/lib/include/chiaki/rpcrypt.h @@ -31,15 +31,18 @@ extern "C" { typedef struct chiaki_rpcrypt_t { + ChiakiTarget target; uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; } 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 *ambassador); +CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(ChiakiTarget target, uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning); +CHIAKI_EXPORT void chiaki_rpcrypt_aeropause_ps4_pre10(uint8_t *aeropause, const uint8_t *ambassador); +CHIAKI_EXPORT void chiaki_rpcrypt_aeropause(size_t key_1_off, uint8_t *aeropause, const uint8_t *ambassador); -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 *ambassador, uint32_t pin); +CHIAKI_EXPORT void chiaki_rpcrypt_init_auth(ChiakiRPCrypt *rpcrypt, ChiakiTarget target, const uint8_t *nonce, const uint8_t *morning); +CHIAKI_EXPORT void chiaki_rpcrypt_init_regist_ps4_pre10(ChiakiRPCrypt *rpcrypt, const uint8_t *ambassador, uint32_t pin); +CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_init_regist(ChiakiRPCrypt *rpcrypt, const uint8_t *ambassador, size_t key_0_off, 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, const uint8_t *in, uint8_t *out, size_t sz); CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_decrypt(ChiakiRPCrypt *rpcrypt, uint64_t counter, const uint8_t *in, uint8_t *out, size_t sz); diff --git a/lib/include/chiaki/session.h b/lib/include/chiaki/session.h index a18ccfb..81d5fe3 100644 --- a/lib/include/chiaki/session.h +++ b/lib/include/chiaki/session.h @@ -43,22 +43,16 @@ extern "C" { #define CHIAKI_RP_APPLICATION_REASON_IN_USE 0x80108b10 #define CHIAKI_RP_APPLICATION_REASON_CRASH 0x80108b15 #define CHIAKI_RP_APPLICATION_REASON_RP_VERSION 0x80108b11 -// unknown: 0x80108bff +#define CHIAKI_RP_APPLICATION_REASON_UNKNOWN 0x80108bff CHIAKI_EXPORT const char *chiaki_rp_application_reason_string(uint32_t reason); -typedef enum { - CHIAKI_RP_VERSION_UNKNOWN = 0, - CHIAKI_RP_VERSION_8_0 = 800, - CHIAKI_RP_VERSION_9_0 = 900 -} ChiakiRpVersion; - /** * @return RP-Version string or NULL */ -CHIAKI_EXPORT const char *chiaki_rp_version_string(ChiakiRpVersion version); +CHIAKI_EXPORT const char *chiaki_rp_version_string(ChiakiTarget target); -CHIAKI_EXPORT ChiakiRpVersion chiaki_rp_version_parse(const char *rp_version_str); +CHIAKI_EXPORT ChiakiTarget chiaki_rp_version_parse(const char *rp_version_str); #define CHIAKI_RP_DID_SIZE 32 @@ -171,7 +165,7 @@ typedef struct chiaki_session_t ChiakiConnectVideoProfile video_profile; } connect_info; - ChiakiRpVersion rp_version; + ChiakiTarget target; uint8_t nonce[CHIAKI_RPCRYPT_KEY_SIZE]; ChiakiRPCrypt rpcrypt; diff --git a/lib/src/ctrl.c b/lib/src/ctrl.c index 3304344..bca281f 100644 --- a/lib/src/ctrl.c +++ b/lib/src/ctrl.c @@ -576,9 +576,23 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl) if(err != CHIAKI_ERR_SUCCESS) goto error; + char bitrate_b64[256]; + bool have_bitrate = session->target >= CHIAKI_TARGET_PS4_10; + if(have_bitrate) + { + uint8_t bitrate[4] = { 0 }; + uint8_t bitrate_enc[4] = { 0 }; + err = chiaki_rpcrypt_encrypt(&session->rpcrypt, ctrl->crypt_counter_local++, (const uint8_t *)bitrate, bitrate_enc, 4); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + + err = chiaki_base64_encode(bitrate_enc, 4, bitrate_b64, sizeof(bitrate_b64)); + if(err != CHIAKI_ERR_SUCCESS) + goto error; + } static const char request_fmt[] = - "GET /sce/rp/session/ctrl HTTP/1.1\r\n" + "GET %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: remoteplay Windows\r\n" "Connection: keep-alive\r\n" @@ -589,17 +603,27 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl) "RP-ControllerType: 3\r\n" "RP-ClientType: 11\r\n" "RP-OSType: %s\r\n" - "RP-ConPath: 1\r\n\r\n"; + "RP-ConPath: 1\r\n" + "%s%s%s" + "\r\n"; - const char *rp_version = chiaki_rp_version_string(session->rp_version); + const char *path = (session->target == CHIAKI_TARGET_PS4_8 || session->target == CHIAKI_TARGET_PS4_9) + ? "/sce/rp/session/ctrl" + : "/sie/ps4/rp/sess/ctrl"; + const char *rp_version = chiaki_rp_version_string(session->target); char buf[512]; int request_len = snprintf(buf, sizeof(buf), request_fmt, - session->connect_info.hostname, SESSION_CTRL_PORT, auth_b64, rp_version ? rp_version : "", did_b64, ostype_b64); + path, session->connect_info.hostname, SESSION_CTRL_PORT, auth_b64, + rp_version ? rp_version : "", did_b64, ostype_b64, + have_bitrate ? "RP-StartBitrate: " : "", + have_bitrate ? bitrate_b64 : "", + have_bitrate ? "\r\n" : ""); if(request_len < 0 || request_len >= sizeof(buf)) goto error; CHIAKI_LOGI(session->log, "Sending ctrl request"); + chiaki_log_hexdump(session->log, CHIAKI_LOG_VERBOSE, (const uint8_t *)buf, (size_t)request_len); int sent = send(sock, buf, (size_t)request_len, 0); if(sent < 0) diff --git a/lib/src/regist.c b/lib/src/regist.c index a50504e..6cc6e18 100644 --- a/lib/src/regist.c +++ b/lib/src/regist.c @@ -106,34 +106,42 @@ static void regist_event_simple(ChiakiRegist *regist, ChiakiRegistEventType type regist->cb(&event, regist->cb_user); } -static const char * const request_head_fmt = - "POST /sce/rp/regist HTTP/1.1\r\n" +static const char *const request_head_fmt = + "POST %s HTTP/1.1\r\n 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"; -static const char * const request_rp_version_fmt = "RP-Version: %s\r\n"; +static const char *request_path = "/sie/ps4/rp/sess/rgst"; +static const char *request_path_ps4_pre10 = "/sce/rp/regist"; -static const char * const request_tail = "\r\n"; +static const char *const request_rp_version_fmt = "RP-Version: %s\r\n"; -static const char * const request_inner_account_id_fmt = - "Client-Type: Windows\r\n" +static const char *const request_tail = "\r\n"; + +const char *client_type = "dabfa2ec873de5839bee8d3f4c0239c4282c07c25c6077a2931afcf0adc0d34f"; +const char *client_type_ps4_pre10 = "Windows"; + +static const char *const request_inner_account_id_fmt = + "Client-Type: %s\r\n" "Np-AccountId: %s\r\n"; -static const char * const request_inner_online_id_fmt = +static const char *const request_inner_online_id_fmt = "Client-Type: Windows\r\n" "Np-Online-Id: %s\r\n"; -static int request_header_format(char *buf, size_t buf_size, size_t payload_size, ChiakiRpVersion rp_version) +static int request_header_format(char *buf, size_t buf_size, size_t payload_size, ChiakiTarget target) { - int cur = snprintf(buf, buf_size, request_head_fmt, (unsigned long long)payload_size); + int cur = snprintf(buf, buf_size, request_head_fmt, + target < CHIAKI_TARGET_PS4_10 ? request_path_ps4_pre10 : request_path, + (unsigned long long)payload_size); if(cur < 0 || cur >= payload_size) return -1; - if(rp_version >= CHIAKI_RP_VERSION_9_0) + if(target >= CHIAKI_TARGET_PS4_9) { - const char *rp_version_str = chiaki_rp_version_string(rp_version); + const char *rp_version_str = chiaki_rp_version_string(target); size_t s = buf_size - cur; int r = snprintf(buf + cur, s, request_rp_version_fmt, rp_version_str); if(r < 0 || r >= s) @@ -149,14 +157,31 @@ static int request_header_format(char *buf, size_t buf_size, size_t payload_size } -CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id) +CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(ChiakiTarget target, const uint8_t *ambassador, uint8_t *buf, size_t *buf_size, ChiakiRPCrypt *crypt, const char *psn_online_id, const uint8_t *psn_account_id, uint32_t pin) { size_t buf_size_val = *buf_size; static const size_t inner_header_off = 0x1e0; if(buf_size_val < inner_header_off) return CHIAKI_ERR_BUF_TOO_SMALL; - memset(buf, 'A', inner_header_off); - chiaki_rpcrypt_aeropause(buf + 0x11c, crypt->ambassador); + memset(buf, 'A', inner_header_off); // can be random + + if(target < CHIAKI_TARGET_PS4_10) + { + chiaki_rpcrypt_init_regist_ps4_pre10(crypt, ambassador, pin); + chiaki_rpcrypt_aeropause_ps4_pre10(buf + 0x11c, crypt->ambassador); + } + else + { + size_t key_0_off = buf[0x18D] & 0x1F; + size_t key_1_off = buf[0] >> 3; + chiaki_rpcrypt_init_regist(crypt, ambassador, key_0_off, pin); + uint8_t aeropause[0x10]; + chiaki_rpcrypt_aeropause(key_1_off, aeropause, crypt->ambassador); + memcpy(buf + 0xc7, aeropause + 8, 8); + memcpy(buf + 0x191, aeropause, 8); + psn_online_id = NULL; // don't need this + } + int inner_header_size; if(psn_online_id) inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, request_inner_online_id_fmt, psn_online_id); @@ -166,7 +191,10 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_regist_request_payload_format(uint8_t *buf, ChiakiErrorCode err = chiaki_base64_encode(psn_account_id, CHIAKI_PSN_ACCOUNT_ID_SIZE, account_id_b64, sizeof(account_id_b64)); if(err != CHIAKI_ERR_SUCCESS) return err; - inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, request_inner_account_id_fmt, account_id_b64); + inner_header_size = snprintf((char *)buf + inner_header_off, buf_size_val - inner_header_off, + request_inner_account_id_fmt, + target < CHIAKI_TARGET_PS4_10 ? client_type_ps4_pre10 : client_type, + account_id_b64); } else return CHIAKI_ERR_INVALID_DATA; @@ -184,29 +212,26 @@ static void *regist_thread_func(void *user) bool canceled = false; bool success = false; + ChiakiRPCrypt crypt; uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; ChiakiErrorCode err = chiaki_random_bytes_crypt(ambassador, sizeof(ambassador)); if(err != CHIAKI_ERR_SUCCESS) { - CHIAKI_LOGE(regist->log, "Regist failed to generate random nonce"); + CHIAKI_LOGE(regist->log, "Regist failed to generate random ambassador"); goto fail; } - ChiakiRPCrypt crypt; - chiaki_rpcrypt_init_regist(&crypt, ambassador, regist->info.pin); - uint8_t payload[0x400]; size_t payload_size = sizeof(payload); - err = chiaki_regist_request_payload_format(payload, &payload_size, &crypt, regist->info.psn_online_id, regist->info.psn_account_id); + err = chiaki_regist_request_payload_format(regist->info.target, ambassador, payload, &payload_size, &crypt, regist->info.psn_online_id, regist->info.psn_account_id, regist->info.pin); if(err != CHIAKI_ERR_SUCCESS) { CHIAKI_LOGE(regist->log, "Regist failed to format payload"); goto fail; } - ChiakiRpVersion rp_version = regist->info.psn_online_id ? CHIAKI_RP_VERSION_8_0 : CHIAKI_RP_VERSION_9_0; char request_header[0x100]; - int request_header_size = request_header_format(request_header, sizeof(request_header), payload_size, rp_version); + int request_header_size = request_header_format(request_header, sizeof(request_header), payload_size, regist->info.target); if(request_header_size < 0 || request_header_size >= sizeof(request_header)) { diff --git a/lib/src/rpcrypt.c b/lib/src/rpcrypt.c index 5659105..a791d6b 100644 --- a/lib/src/rpcrypt.c +++ b/lib/src/rpcrypt.c @@ -31,7 +31,7 @@ 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 void bright_ambassador_ps4_pre10(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 }; @@ -55,7 +55,768 @@ 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 *ambassador) +static void bright_ambassador(uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning) +{ + static const uint8_t static_keys_a[0x70 * 0x20] = { + 0xdf, 0x40, 0x82, 0xa6, 0x2e, 0xd8, 0x6b, 0x2b, 0xf5, 0x6c, + 0x5f, 0xf5, 0xfb, 0x21, 0x69, 0xb4, 0x00, 0x27, 0x5e, 0x87, + 0xfa, 0x1a, 0xa7, 0x95, 0x16, 0xa1, 0xb7, 0xb7, 0xca, 0xf2, + 0x3d, 0x7a, 0x04, 0x97, 0xef, 0x49, 0xeb, 0x51, 0xbc, 0xe9, + 0x2a, 0x47, 0x84, 0xba, 0xfb, 0x08, 0x78, 0x4a, 0xa7, 0x82, + 0x17, 0xad, 0x4b, 0x26, 0x34, 0x97, 0xb2, 0xde, 0x41, 0x7d, + 0xc6, 0x08, 0xc4, 0xe9, 0xe7, 0x73, 0xa1, 0x22, 0xa2, 0xf3, + 0x2a, 0x6f, 0x8c, 0xc0, 0x45, 0xf6, 0x84, 0xb4, 0xd7, 0x54, + 0x07, 0xd5, 0x76, 0x33, 0xd3, 0x8b, 0x61, 0xe7, 0xea, 0xd6, + 0x98, 0x32, 0xf5, 0xeb, 0x9e, 0x1b, 0xbd, 0xe2, 0x01, 0x31, + 0x45, 0x01, 0x0d, 0x51, 0x1f, 0x77, 0xaf, 0x0c, 0x34, 0xb7, + 0x23, 0x40, 0x0d, 0xc0, 0xac, 0x7e, 0x04, 0xb5, 0xf0, 0x75, + 0xde, 0x5e, 0xba, 0xfa, 0xa6, 0x25, 0x56, 0xde, 0x53, 0x83, + 0x94, 0x4e, 0xa4, 0xd9, 0x4e, 0xf4, 0x73, 0xab, 0xd6, 0x96, + 0xb6, 0xfc, 0x09, 0x46, 0xe2, 0x1a, 0x9d, 0x4f, 0xf1, 0x89, + 0x90, 0xa0, 0x34, 0xf4, 0x55, 0x60, 0x29, 0xf9, 0x39, 0xdb, + 0x20, 0xaa, 0xdf, 0x8b, 0xff, 0x6c, 0xc0, 0xa9, 0x96, 0xad, + 0x71, 0x67, 0xae, 0xb6, 0x1a, 0x6e, 0xd4, 0x92, 0x7a, 0xc7, + 0xac, 0x31, 0xc8, 0x21, 0x24, 0x3b, 0xb3, 0x6a, 0x1d, 0x4d, + 0xc0, 0x82, 0x5f, 0x53, 0x9f, 0xf9, 0xeb, 0x4a, 0x41, 0x47, + 0x27, 0x5a, 0xbc, 0x3b, 0xc8, 0x50, 0x20, 0xeb, 0x11, 0x02, + 0xf8, 0xc5, 0x7e, 0xa4, 0xd3, 0x85, 0x52, 0x90, 0x61, 0x4e, + 0x88, 0xff, 0x81, 0xcf, 0x75, 0x58, 0x21, 0xfe, 0x58, 0x8f, + 0xd0, 0x75, 0xf6, 0x20, 0xaa, 0x54, 0x3a, 0x45, 0x54, 0xf3, + 0xe4, 0x44, 0xda, 0x98, 0x7f, 0x09, 0x9e, 0xa6, 0x72, 0x63, + 0xbc, 0x9f, 0x46, 0x77, 0x7e, 0x24, 0xf8, 0xda, 0xc4, 0x94, + 0x04, 0xa9, 0x23, 0xa7, 0xea, 0x67, 0xe3, 0x85, 0x41, 0xa4, + 0x4b, 0x8e, 0xc1, 0x92, 0xde, 0x96, 0xc8, 0x09, 0xb7, 0xd4, + 0x41, 0x60, 0x89, 0xf0, 0xdb, 0x09, 0x56, 0x01, 0xc1, 0x6c, + 0x33, 0xb1, 0x37, 0xbd, 0x79, 0x6f, 0xab, 0x1c, 0x61, 0xe9, + 0x18, 0xfc, 0xb3, 0x6c, 0xbc, 0xfe, 0xea, 0xb1, 0x9e, 0xce, + 0xba, 0x83, 0xda, 0xe5, 0x81, 0xd7, 0x07, 0xb7, 0x8a, 0xf0, + 0x89, 0x39, 0xdc, 0x30, 0x6b, 0x0d, 0xa7, 0x2b, 0xc9, 0x51, + 0xdc, 0x4f, 0x99, 0x98, 0x3c, 0xcf, 0x62, 0x1c, 0x56, 0xf1, + 0x86, 0x88, 0xdb, 0xce, 0x10, 0xbf, 0x3d, 0xde, 0xe6, 0xf5, + 0x02, 0x51, 0xf7, 0xa5, 0xe3, 0x0a, 0xdb, 0xeb, 0xae, 0xb0, + 0x76, 0x89, 0x62, 0x4b, 0xa7, 0xbd, 0xd6, 0xfe, 0x8d, 0x01, + 0x28, 0x26, 0xf3, 0x76, 0x65, 0xba, 0x0f, 0x44, 0x77, 0x65, + 0x79, 0x47, 0x06, 0x43, 0xae, 0xa8, 0xd1, 0x5e, 0x20, 0x0e, + 0x72, 0x2a, 0x15, 0xd9, 0x42, 0x96, 0xe7, 0xdb, 0x40, 0xae, + 0x4e, 0x2b, 0x1c, 0x6d, 0x71, 0xa2, 0x8e, 0xa6, 0xe1, 0x4d, + 0xe8, 0x84, 0xa3, 0xa5, 0x59, 0x41, 0x0c, 0x9e, 0xe9, 0x3e, + 0x5a, 0xc8, 0x02, 0x3f, 0xbb, 0xf3, 0xe1, 0x0a, 0xf7, 0x3d, + 0xd7, 0xaa, 0xe5, 0x64, 0xc6, 0x4e, 0xc3, 0xc9, 0xbb, 0x32, + 0x30, 0xa9, 0x18, 0xec, 0xb8, 0xae, 0x61, 0xc9, 0x1a, 0x62, + 0xeb, 0x47, 0x92, 0x0c, 0xa7, 0xe0, 0x6c, 0x33, 0xf5, 0x84, + 0xec, 0x69, 0x31, 0xdb, 0xad, 0xdf, 0x3d, 0xbb, 0x4c, 0x4b, + 0xa1, 0x8c, 0xf0, 0x46, 0x52, 0x65, 0x72, 0xaf, 0x6a, 0xc8, + 0xce, 0xb3, 0x27, 0xd3, 0x32, 0x78, 0xb1, 0x39, 0xd6, 0xd1, + 0x5e, 0x09, 0x06, 0xff, 0xdc, 0x8f, 0xca, 0x16, 0x9b, 0x5e, + 0xa2, 0x18, 0x64, 0xee, 0x8c, 0x0b, 0x9b, 0xd7, 0x41, 0xf8, + 0x35, 0x98, 0xd3, 0x5c, 0x78, 0xe2, 0xbb, 0xa5, 0xf7, 0x68, + 0x02, 0x8a, 0xd2, 0x14, 0x85, 0x50, 0x8b, 0x98, 0x2a, 0x09, + 0x15, 0xc0, 0x9e, 0x9c, 0x47, 0x1f, 0x92, 0xc2, 0xa5, 0x2a, + 0x3b, 0xaa, 0x7b, 0xde, 0xb8, 0xe7, 0xee, 0xa7, 0xe0, 0x4a, + 0xb4, 0x81, 0x28, 0x7f, 0x15, 0x38, 0xe8, 0x78, 0xff, 0xc1, + 0xed, 0x98, 0xd8, 0x4f, 0x23, 0x3f, 0x77, 0x29, 0xac, 0xa5, + 0xbc, 0xd0, 0x8f, 0x2b, 0x89, 0xb9, 0x99, 0xbe, 0xc1, 0xf1, + 0x3e, 0x4e, 0xbd, 0x30, 0xd7, 0x6c, 0x1c, 0x09, 0x4e, 0x7c, + 0x13, 0x28, 0xf5, 0xc3, 0xff, 0xc1, 0xcf, 0x8a, 0x2a, 0x41, + 0xd0, 0x73, 0x24, 0x23, 0x31, 0x13, 0x77, 0xa4, 0x33, 0xc0, + 0x7e, 0x7b, 0xc0, 0x81, 0xb5, 0xf5, 0x25, 0x80, 0x45, 0xc5, + 0x94, 0x65, 0xa4, 0x8a, 0x94, 0xc1, 0xb6, 0xf4, 0x69, 0x61, + 0x11, 0xd5, 0x43, 0xea, 0x4b, 0x38, 0x4a, 0x56, 0x14, 0xdd, + 0x3b, 0xa6, 0x99, 0xdf, 0xe5, 0x87, 0x2a, 0xf9, 0x12, 0xbf, + 0x45, 0xb1, 0xd9, 0x74, 0x67, 0x8b, 0x2b, 0x57, 0xc3, 0xd0, + 0xb1, 0x9a, 0x4a, 0xcc, 0x4f, 0x63, 0x79, 0x5a, 0x4f, 0x1d, + 0xa6, 0xff, 0x65, 0xee, 0xbe, 0xd9, 0x16, 0xea, 0xa9, 0x66, + 0x07, 0x97, 0x71, 0x43, 0xdd, 0x64, 0xe3, 0x00, 0x03, 0xbc, + 0xba, 0x1b, 0xf3, 0xa6, 0xa6, 0xee, 0xef, 0xf8, 0xa7, 0xf2, + 0x15, 0xf9, 0xcf, 0x8c, 0x62, 0x2a, 0x1e, 0x9b, 0xbe, 0xfb, + 0x5a, 0xb7, 0xed, 0xd5, 0xd2, 0x71, 0x2a, 0xc9, 0xeb, 0x65, + 0x68, 0x77, 0x34, 0xa4, 0xbb, 0x44, 0xab, 0x01, 0xe5, 0x79, + 0x19, 0x37, 0xb2, 0x07, 0x01, 0xc6, 0xca, 0xb3, 0x07, 0xb8, + 0x55, 0xac, 0x03, 0xae, 0xf6, 0x3f, 0x29, 0x12, 0xa1, 0xba, + 0x1d, 0x94, 0x3a, 0xa3, 0xb5, 0x6c, 0x6e, 0xf4, 0x31, 0x3f, + 0x38, 0xa7, 0xe0, 0x34, 0x31, 0xf2, 0x2a, 0x7a, 0xe6, 0xcf, + 0x3f, 0xc4, 0xe9, 0xb9, 0x0f, 0x05, 0x9f, 0xec, 0x9a, 0xdc, + 0xb3, 0x59, 0xc4, 0x61, 0xaa, 0x10, 0xb6, 0xce, 0x73, 0xe3, + 0xe3, 0x8c, 0xf8, 0x5d, 0x0e, 0x95, 0x3e, 0x1a, 0x4f, 0xbe, + 0x77, 0x87, 0xce, 0x8a, 0x17, 0xf5, 0x20, 0xa7, 0x01, 0xf0, + 0xd7, 0xe6, 0x34, 0x63, 0x04, 0x76, 0xbe, 0x74, 0xb3, 0x44, + 0x7d, 0xdf, 0x11, 0x32, 0xb9, 0x13, 0x32, 0x15, 0x1a, 0xed, + 0xcf, 0x1f, 0x85, 0x91, 0xdb, 0xa3, 0xc4, 0xf2, 0x0f, 0x2c, + 0x8f, 0x77, 0x0a, 0xc4, 0x09, 0x7d, 0x19, 0x12, 0x7c, 0x46, + 0xf7, 0x9d, 0x3a, 0x94, 0x86, 0x4b, 0x22, 0x67, 0x6f, 0x90, + 0x57, 0x99, 0x70, 0x28, 0x3d, 0x9c, 0x53, 0xd2, 0xd3, 0x0b, + 0xc1, 0x29, 0xb7, 0x39, 0x8c, 0xb7, 0x62, 0xc8, 0xbb, 0x64, + 0x4d, 0xcf, 0xe0, 0x5f, 0x64, 0xfc, 0x47, 0xb2, 0xef, 0x0a, + 0x68, 0x8d, 0x9a, 0xcd, 0x9f, 0x49, 0x77, 0x6b, 0x50, 0x47, + 0x7c, 0xfc, 0xa4, 0xd4, 0x2c, 0x4d, 0x53, 0xc1, 0x26, 0x26, + 0x92, 0x38, 0x0d, 0xba, 0x1c, 0x71, 0x81, 0x17, 0x4a, 0x59, + 0x0f, 0x80, 0xfd, 0xad, 0x69, 0x5c, 0x58, 0xa7, 0xff, 0xef, + 0x1a, 0xca, 0xd6, 0xfb, 0x7e, 0x09, 0xdc, 0x32, 0x17, 0x34, + 0x31, 0x9c, 0xfa, 0x78, 0xf9, 0x88, 0x1a, 0x50, 0x6b, 0x09, + 0x24, 0xfe, 0x75, 0xcd, 0x22, 0xbd, 0xf0, 0x12, 0x10, 0x9d, + 0xc5, 0x7b, 0xbe, 0x9f, 0xa4, 0xc8, 0x7a, 0x7c, 0xb1, 0xa7, + 0x46, 0x2d, 0x48, 0xa1, 0x08, 0xd8, 0x75, 0x3c, 0x40, 0x53, + 0x59, 0x5a, 0x04, 0xf6, 0xcb, 0xd6, 0x2f, 0x51, 0x9e, 0x4a, + 0xa8, 0xef, 0x02, 0x3c, 0x61, 0xa8, 0x45, 0x5a, 0x99, 0x9a, + 0x73, 0x09, 0xc0, 0x71, 0x6f, 0x4d, 0xb7, 0x2c, 0x69, 0x6c, + 0x1e, 0x85, 0x48, 0xea, 0x33, 0x5b, 0xb1, 0x28, 0x09, 0xe3, + 0x24, 0x47, 0x7a, 0x12, 0xd8, 0x77, 0xa0, 0xfd, 0x3c, 0xcd, + 0x23, 0x53, 0x61, 0xf0, 0x9e, 0x49, 0x44, 0x19, 0x9c, 0xe1, + 0x0a, 0xb6, 0xc5, 0x93, 0x35, 0x4d, 0x06, 0xde, 0xb5, 0xac, + 0x15, 0xe2, 0x8d, 0x47, 0x6a, 0x8a, 0x29, 0x58, 0x8f, 0xfc, + 0x2b, 0x32, 0xc4, 0x0e, 0x4e, 0x75, 0xb2, 0x71, 0x44, 0x91, + 0xb6, 0xfb, 0x50, 0x60, 0xc4, 0x50, 0x4d, 0xd9, 0x1c, 0xd7, + 0x28, 0xb5, 0x2e, 0x08, 0x82, 0xfd, 0xbd, 0x7c, 0x48, 0x62, + 0x00, 0x01, 0x30, 0xa5, 0x47, 0x2a, 0x10, 0x4b, 0xfe, 0x3e, + 0xb5, 0xd7, 0xe2, 0x1e, 0x5a, 0xd0, 0xe3, 0x6b, 0xa0, 0x9c, + 0xe3, 0x12, 0x05, 0xb9, 0x1c, 0x7b, 0x3f, 0x18, 0x88, 0x11, + 0xc3, 0x4d, 0xe8, 0x83, 0x78, 0xf1, 0x8c, 0x6a, 0xb3, 0x87, + 0x7f, 0x67, 0xdf, 0x47, 0xc4, 0x2f, 0xea, 0x9c, 0x79, 0x98, + 0x35, 0x2d, 0x7b, 0x2d, 0xc7, 0x3e, 0x31, 0x13, 0x6e, 0xf3, + 0xfd, 0xa8, 0x16, 0x25, 0x03, 0x3f, 0xb1, 0x14, 0x77, 0xff, + 0xa1, 0xf2, 0xe9, 0x98, 0x32, 0xe4, 0x2f, 0x3e, 0xb0, 0x6e, + 0x29, 0x84, 0x0f, 0xdd, 0x85, 0xbb, 0xda, 0x0a, 0xc6, 0x19, + 0x78, 0x9a, 0x6b, 0xdd, 0x8b, 0x40, 0x39, 0x1f, 0x19, 0xce, + 0xad, 0x79, 0xc9, 0xda, 0x59, 0xbf, 0x6e, 0xbc, 0xb0, 0xc8, + 0x6e, 0x61, 0xeb, 0x2e, 0xba, 0xa6, 0x50, 0x06, 0x8c, 0x74, + 0xab, 0x23, 0x4f, 0x9d, 0x9e, 0x20, 0x67, 0x9a, 0x0c, 0xea, + 0x60, 0x14, 0x85, 0x42, 0xc4, 0x7d, 0xc0, 0x1c, 0x62, 0xa5, + 0x7e, 0x65, 0x1d, 0xee, 0xa1, 0xfd, 0xed, 0x82, 0x19, 0x1e, + 0x90, 0x87, 0xab, 0xdb, 0x80, 0xb7, 0xb2, 0xab, 0xa0, 0xbc, + 0xdb, 0x99, 0x9b, 0x2e, 0x8e, 0xc4, 0x96, 0xfe, 0x31, 0x82, + 0x9e, 0xe9, 0xc9, 0xa3, 0xd0, 0xe3, 0x52, 0x0f, 0x73, 0x24, + 0xd7, 0xb6, 0x41, 0xcc, 0xfc, 0xae, 0x86, 0xb5, 0x79, 0xe5, + 0x25, 0xc8, 0x76, 0x60, 0x48, 0x3c, 0xa4, 0x74, 0x6a, 0x7b, + 0x7e, 0xa8, 0x5b, 0xf8, 0x5b, 0x79, 0x0f, 0x19, 0x95, 0x7d, + 0x7f, 0x56, 0x31, 0xcc, 0x34, 0xd0, 0xb8, 0x0c, 0x29, 0x3f, + 0x83, 0x54, 0x02, 0x75, 0xe3, 0x79, 0xb6, 0x64, 0xf9, 0x66, + 0x7f, 0x90, 0xe1, 0xa7, 0x7b, 0xfa, 0x17, 0x68, 0x07, 0xd1, + 0xef, 0x35, 0x52, 0xf3, 0x56, 0xde, 0x35, 0x35, 0x14, 0x1b, + 0xcd, 0x97, 0x1a, 0xe5, 0xf4, 0xb5, 0xae, 0xfc, 0x53, 0x0c, + 0xec, 0x36, 0xf0, 0xb4, 0x30, 0xea, 0x9b, 0xde, 0x60, 0x31, + 0x72, 0x7e, 0x99, 0x41, 0x78, 0x90, 0x81, 0x73, 0x0a, 0x81, + 0xe2, 0xaa, 0x70, 0x68, 0x67, 0x7a, 0x52, 0x4a, 0x4d, 0xd4, + 0x9f, 0x90, 0x0d, 0xd9, 0x3a, 0x1f, 0x8d, 0x80, 0xfa, 0x68, + 0x62, 0x54, 0xae, 0xb7, 0x0f, 0x3a, 0xfa, 0xed, 0xc9, 0xce, + 0x20, 0x8d, 0x88, 0x48, 0x79, 0x82, 0x8a, 0xf6, 0xc5, 0x4d, + 0x6e, 0xed, 0x38, 0x81, 0x75, 0x65, 0xac, 0xf6, 0x72, 0xee, + 0xf0, 0x2e, 0x6d, 0x3f, 0x2e, 0x2a, 0x54, 0xf2, 0xf1, 0x5a, + 0xb9, 0x81, 0xce, 0x56, 0xbf, 0xed, 0xab, 0xd5, 0x32, 0xf1, + 0x95, 0x86, 0x81, 0xf9, 0xfd, 0x38, 0x1d, 0xc7, 0x9f, 0x55, + 0xe1, 0x2c, 0xd1, 0x28, 0x66, 0x26, 0x81, 0xf5, 0x12, 0x72, + 0x02, 0x35, 0x87, 0x65, 0x01, 0xea, 0x4f, 0xf7, 0x95, 0xba, + 0xb1, 0x09, 0x91, 0x9c, 0x89, 0xb4, 0x48, 0x1d, 0x7b, 0xb4, + 0x37, 0x76, 0x6c, 0xce, 0x83, 0x0e, 0x2c, 0xb8, 0xd5, 0xe0, + 0x43, 0x36, 0x3c, 0x2d, 0xb1, 0x0f, 0x29, 0x4e, 0x1d, 0x36, + 0x58, 0x9a, 0xcd, 0xf4, 0xa7, 0xad, 0xae, 0xdb, 0x8f, 0x59, + 0xd0, 0x78, 0xb4, 0xcb, 0xfd, 0xe6, 0x1b, 0xa9, 0x24, 0x26, + 0xb7, 0xa2, 0xc0, 0xbd, 0x08, 0x53, 0xd2, 0x4e, 0xb2, 0x19, + 0x90, 0xb1, 0xb0, 0xa7, 0x57, 0xaa, 0xeb, 0x11, 0x71, 0xdd, + 0x3b, 0xae, 0x04, 0xf4, 0x44, 0xa5, 0x27, 0xeb, 0xb3, 0x2e, + 0xdd, 0x70, 0x7e, 0x0d, 0x2b, 0x2f, 0xc4, 0x4c, 0xee, 0xff, + 0x4d, 0x94, 0xde, 0x6f, 0x48, 0xa1, 0x7b, 0xa2, 0xa2, 0xef, + 0x3a, 0xa3, 0x0c, 0x99, 0x4e, 0x6e, 0xd4, 0x64, 0xbb, 0xd2, + 0xa0, 0x38, 0x39, 0xe8, 0x16, 0xa3, 0x4b, 0x77, 0xb7, 0xa4, + 0xf6, 0xc0, 0x12, 0xec, 0xfe, 0x97, 0xc0, 0xa4, 0xfc, 0x90, + 0x8c, 0x07, 0xfb, 0x0a, 0xc9, 0x4f, 0xe8, 0xf7, 0x6e, 0x45, + 0xf6, 0xab, 0x8b, 0xb1, 0x58, 0x56, 0x5b, 0xda, 0x12, 0xc0, + 0x4c, 0xe1, 0x74, 0x1c, 0xb9, 0x14, 0xdf, 0xe4, 0x17, 0x53, + 0xb3, 0x0c, 0xe2, 0xe1, 0xbc, 0xfc, 0xe6, 0x9c, 0xed, 0xed, + 0x82, 0x20, 0x2a, 0x4d, 0xdf, 0xd8, 0x78, 0x6e, 0xf5, 0x16, + 0x57, 0x48, 0x58, 0x9a, 0xb6, 0x57, 0x20, 0xf0, 0x74, 0xcc, + 0xcf, 0xdd, 0x5c, 0xf4, 0xd6, 0x7e, 0xc4, 0x53, 0x13, 0xa4, + 0xf1, 0x68, 0xc5, 0xa4, 0xe1, 0x91, 0x58, 0xcf, 0x5c, 0x9f, + 0x36, 0xbf, 0x20, 0x21, 0x1b, 0x34, 0x5c, 0xbd, 0x2c, 0x64, + 0xc5, 0x6f, 0x7f, 0xb9, 0x91, 0x65, 0xcf, 0x25, 0x44, 0x93, + 0x99, 0x1f, 0xb9, 0x82, 0xeb, 0xc5, 0x3b, 0x4f, 0xd2, 0xad, + 0x5e, 0xaf, 0x69, 0xfc, 0x2f, 0x54, 0xe4, 0xd0, 0x34, 0xdb, + 0x47, 0xef, 0x8b, 0x16, 0x54, 0x2b, 0x67, 0x27, 0x3c, 0x50, + 0x9f, 0xf0, 0x6c, 0xe6, 0xe2, 0x08, 0xd0, 0x0a, 0x36, 0x76, + 0xc1, 0x65, 0x62, 0x01, 0x4d, 0x70, 0xb8, 0x42, 0xe4, 0x88, + 0xee, 0x63, 0x0b, 0x74, 0x64, 0x2b, 0x15, 0xf1, 0x90, 0x6c, + 0xa3, 0x3f, 0xf4, 0x94, 0xca, 0x3f, 0x48, 0x64, 0x5a, 0x09, + 0x36, 0x5c, 0x7c, 0x4f, 0x75, 0xf0, 0x4e, 0xe3, 0x3d, 0xf3, + 0x6d, 0x9b, 0x4f, 0x99, 0x29, 0xf1, 0xe2, 0xff, 0x92, 0x38, + 0x5d, 0xf6, 0xf3, 0xd2, 0xc5, 0x5d, 0x1d, 0x89, 0x78, 0x09, + 0xbb, 0x6a, 0x3a, 0x0a, 0x9c, 0x01, 0x4c, 0xd9, 0xfd, 0x55, + 0x48, 0xa1, 0xf7, 0xa1, 0x9c, 0x55, 0xc1, 0x31, 0xaf, 0xa5, + 0x03, 0xbb, 0xba, 0x8c, 0x76, 0x0a, 0xf0, 0xd6, 0x03, 0x57, + 0x71, 0xf5, 0xfe, 0xad, 0x7f, 0x36, 0x23, 0x57, 0xba, 0x9b, + 0x20, 0x92, 0x14, 0x9e, 0xcf, 0x76, 0x59, 0xcd, 0xe2, 0x47, + 0x12, 0xb4, 0x1e, 0xb5, 0x52, 0xc3, 0x7f, 0xda, 0xa0, 0x35, + 0xc2, 0x55, 0x56, 0x97, 0xd0, 0x57, 0xa0, 0xcc, 0xcd, 0x27, + 0xcc, 0x08, 0x1c, 0x9c, 0x06, 0xfd, 0xbe, 0x47, 0xdf, 0x78, + 0x08, 0x17, 0xb6, 0x7f, 0x31, 0x1e, 0x0a, 0xdc, 0x54, 0xcc, + 0x06, 0xf7, 0xbf, 0xee, 0x74, 0x48, 0x21, 0x39, 0x6c, 0xf0, + 0x1f, 0x29, 0x19, 0x76, 0x19, 0x7f, 0xc2, 0x38, 0x94, 0x8a, + 0xe4, 0x2d, 0x7f, 0xff, 0xf7, 0x45, 0x57, 0x21, 0x98, 0xaa, + 0x65, 0x35, 0xba, 0x3c, 0x56, 0xff, 0x62, 0x88, 0xb9, 0xe8, + 0xe9, 0xdb, 0xd1, 0xf8, 0x59, 0x0f, 0x50, 0x13, 0x8b, 0xc2, + 0xc2, 0xbd, 0xba, 0x44, 0x44, 0x36, 0xe1, 0xb0, 0x13, 0x32, + 0x3a, 0x68, 0x4d, 0x62, 0xa8, 0x50, 0x87, 0x44, 0xbb, 0x31, + 0xfb, 0xe3, 0x25, 0x73, 0xa0, 0xf1, 0x2c, 0xf5, 0x34, 0x19, + 0x09, 0x66, 0xa9, 0x46, 0x21, 0xc7, 0xa2, 0x91, 0x7d, 0xe9, + 0xf4, 0x9d, 0xa9, 0x82, 0x28, 0xf4, 0x1f, 0x28, 0xa8, 0xa9, + 0x01, 0xf1, 0x97, 0x70, 0x9d, 0x61, 0x72, 0xd5, 0x8b, 0x84, + 0xcf, 0xf1, 0x7c, 0xc2, 0x7d, 0xa7, 0xa3, 0x25, 0x4f, 0x68, + 0x3f, 0x5e, 0x8e, 0xb6, 0x16, 0x18, 0x78, 0xcf, 0x63, 0x53, + 0x57, 0x08, 0x11, 0x55, 0x65, 0x1b, 0x55, 0x5e, 0x8d, 0xce, + 0x68, 0x2d, 0x77, 0x16, 0x1e, 0x87, 0xa6, 0xd0, 0x11, 0x44, + 0x37, 0x8f, 0xa2, 0x8b, 0xb0, 0xdb, 0x4b, 0x01, 0x2f, 0xd7, + 0x1e, 0x16, 0x93, 0xb5, 0x19, 0xad, 0xb7, 0xde, 0x13, 0x0d, + 0xac, 0xcd, 0x77, 0x6a, 0x15, 0x61, 0xeb, 0xe0, 0xd1, 0xbf, + 0xcf, 0x69, 0x10, 0x28, 0x72, 0x58, 0xfe, 0xc7, 0xce, 0xbc, + 0x92, 0xfd, 0x5f, 0x9c, 0xd6, 0x6d, 0x56, 0xbd, 0x39, 0x35, + 0xe0, 0xa6, 0x73, 0x19, 0x45, 0x6a, 0xf2, 0x36, 0x8a, 0x0a, + 0x58, 0xe1, 0x23, 0x07, 0x28, 0xa4, 0x89, 0x7a, 0x51, 0xbb, + 0xba, 0xd6, 0x42, 0x78, 0xbb, 0x5f, 0x42, 0x0b, 0xc0, 0x8f, + 0xc9, 0x3c, 0xc3, 0x7e, 0x41, 0x22, 0x94, 0x3c, 0x02, 0xd3, + 0x2c, 0xec, 0xf8, 0x8f, 0x14, 0x62, 0x7c, 0x78, 0x47, 0x73, + 0xe8, 0xd5, 0x40, 0x2d, 0x26, 0x82, 0x72, 0x16, 0xd7, 0xdd, + 0x9e, 0x8d, 0x8e, 0xfb, 0xaf, 0x83, 0x73, 0xd8, 0x4d, 0x85, + 0x28, 0x53, 0x72, 0xc1, 0xb0, 0x08, 0x5a, 0xc6, 0x6e, 0xbe, + 0xf9, 0x21, 0xdd, 0x8c, 0x30, 0xf5, 0x5e, 0xbe, 0xec, 0xcc, + 0xd2, 0x8a, 0x1a, 0xc3, 0xf4, 0x83, 0x98, 0x86, 0x3b, 0x4e, + 0x6d, 0x3e, 0x9e, 0xbe, 0x84, 0x80, 0x2f, 0x27, 0xbb, 0x6a, + 0x3e, 0x51, 0x18, 0xb0, 0x7a, 0x82, 0x82, 0x02, 0x53, 0x6d, + 0x2d, 0x2a, 0xab, 0x4a, 0x2e, 0x3b, 0xa4, 0x88, 0x90, 0x99, + 0x74, 0x10, 0x27, 0xa7, 0xe9, 0x5c, 0x52, 0x5b, 0xf5, 0xb0, + 0x00, 0xc7, 0x52, 0x91, 0x04, 0xc7, 0xff, 0x01, 0xb7, 0x56, + 0x40, 0x9f, 0x56, 0x54, 0xde, 0x96, 0x65, 0x61, 0x76, 0x06, + 0xb6, 0xdb, 0x16, 0xc8, 0x1c, 0x0b, 0xff, 0xf0, 0x73, 0xd0, + 0x89, 0x22, 0x86, 0xc6, 0xac, 0xc5, 0xb1, 0x98, 0x21, 0xd0, + 0x6c, 0x30, 0x92, 0x43, 0xb4, 0xa9, 0x80, 0xc8, 0xdd, 0x6f, + 0xf0, 0x4b, 0x57, 0x80, 0x6d, 0x53, 0xfb, 0xd4, 0x95, 0x39, + 0xde, 0x6e, 0xf5, 0x28, 0x9e, 0x92, 0x94, 0x42, 0x99, 0x42, + 0x4d, 0x02, 0x0a, 0x7b, 0x9b, 0x8f, 0xc6, 0x32, 0xb0, 0xd9, + 0x5d, 0x81, 0x74, 0xd2, 0x76, 0xdb, 0x64, 0x21, 0xdf, 0xc2, + 0xee, 0x5f, 0x77, 0x88, 0x13, 0x60, 0x32, 0xd8, 0x97, 0xf4, + 0x1c, 0x77, 0xe0, 0x49, 0xce, 0x1d, 0xa2, 0xbb, 0x66, 0xca, + 0x27, 0xfd, 0xc1, 0x96, 0x3a, 0x50, 0x4f, 0x1f, 0xbb, 0x56, + 0x24, 0x85, 0x76, 0x77, 0xfd, 0x84, 0x7b, 0xb4, 0x3c, 0x87, + 0x01, 0x09, 0x89, 0x4c, 0x0f, 0x8e, 0x44, 0xc0, 0x49, 0x39, + 0x49, 0x8b, 0x93, 0x09, 0xa6, 0x8d, 0x93, 0xf1, 0x5a, 0x3f, + 0x1f, 0x64, 0x2f, 0xd2, 0xe2, 0xbe, 0x99, 0x38, 0x38, 0xf1, + 0xec, 0x15, 0x46, 0xe3, 0x8a, 0x95, 0xe6, 0x3c, 0xf8, 0xa3, + 0x38, 0xb8, 0xc0, 0x20, 0x5f, 0xcb, 0x36, 0xe4, 0x90, 0x79, + 0x0c, 0x8e, 0xb6, 0xe5, 0x48, 0x23, 0x2d, 0xcb, 0x3c, 0x88, + 0x31, 0x35, 0xe7, 0x8e, 0xfa, 0xf5, 0x81, 0x36, 0x35, 0x96, + 0x98, 0x39, 0xb0, 0x2d, 0xa3, 0xd7, 0x84, 0x3a, 0x92, 0x30, + 0x07, 0x9b, 0x70, 0x61, 0xda, 0xd6, 0x80, 0x94, 0x7b, 0x93, + 0x01, 0x10, 0xe2, 0x03, 0x23, 0x83, 0xc2, 0xef, 0x2f, 0x4e, + 0x31, 0x01, 0x87, 0x0c, 0x0b, 0x0c, 0x1f, 0x20, 0xaa, 0x75, + 0x52, 0xb5, 0xbc, 0xa2, 0x55, 0xd6, 0x06, 0x3f, 0xf1, 0x6a, + 0x1e, 0xa4, 0x00, 0x43, 0xdb, 0x0f, 0x9a, 0xd4, 0xc4, 0x45, + 0x2f, 0x20, 0x94, 0x57, 0xbc, 0x6e, 0xeb, 0x63, 0xda, 0x90, + 0xb2, 0x56, 0x9b, 0x6c, 0x81, 0xb3, 0x15, 0xd3, 0x1d, 0xe1, + 0xe4, 0x75, 0xaa, 0x3b, 0xbf, 0x45, 0x46, 0xd7, 0x0d, 0x31, + 0xb1, 0xf5, 0x8b, 0xfb, 0x5b, 0x3e, 0x48, 0x4b, 0xea, 0x09, + 0x0c, 0x82, 0xd3, 0x7a, 0x45, 0x1c, 0xc2, 0x4d, 0xda, 0x4d, + 0x08, 0xd1, 0x5d, 0x7c, 0xb5, 0x50, 0x24, 0xbf, 0x3b, 0x5a, + 0xb7, 0xca, 0x76, 0xc4, 0xee, 0x64, 0xf7, 0xc7, 0x77, 0x2d, + 0x06, 0x8d, 0x9b, 0xee, 0x7c, 0x6b, 0xf5, 0x6b, 0x8f, 0x62, + 0x4d, 0x37, 0x66, 0x31, 0x5f, 0xde, 0x2b, 0xb2, 0xe4, 0x70, + 0xda, 0xeb, 0x49, 0xe4, 0x1b, 0x1f, 0xdf, 0x45, 0xee, 0x5a, + 0x69, 0x68, 0x59, 0xe5, 0x71, 0x14, 0xcc, 0x4e, 0x73, 0xa4, + 0x20, 0x38, 0x5c, 0xc7, 0xa7, 0x28, 0xd5, 0xa0, 0xbf, 0xfd, + 0x6a, 0x0f, 0x92, 0x6f, 0x02, 0x64, 0x49, 0x19, 0xe4, 0x18, + 0x23, 0xa2, 0xda, 0x9b, 0x75, 0x7b, 0xc8, 0xdb, 0x8f, 0x78, + 0x68, 0x4c, 0x67, 0x47, 0x82, 0xf6, 0x10, 0x44, 0x23, 0x36, + 0x74, 0x02, 0x58, 0xad, 0x75, 0xd4, 0xad, 0x59, 0x9e, 0x2e, + 0x99, 0x67, 0xc2, 0x5b, 0x89, 0x91, 0x01, 0x37, 0x2e, 0xfe, + 0x50, 0xc4, 0x6d, 0xe7, 0x8b, 0x34, 0x53, 0x22, 0xd0, 0xc3, + 0x1f, 0x16, 0xc9, 0x14, 0x2f, 0x0b, 0x76, 0xdf, 0x29, 0xb9, + 0x32, 0xd4, 0xcd, 0x5e, 0x04, 0xdb, 0xf5, 0x47, 0x3f, 0x99, + 0x26, 0xcb, 0x6b, 0xac, 0xae, 0x2b, 0xbc, 0x75, 0xf2, 0x8d, + 0x64, 0xff, 0xd2, 0x2b, 0xfb, 0x8c, 0x81, 0x79, 0xed, 0x8d, + 0x86, 0x89, 0xc7, 0xfd, 0xe8, 0xde, 0x1a, 0xe1, 0x96, 0x30, + 0xba, 0xe3, 0x8d, 0xc8, 0x43, 0xd5, 0x97, 0x52, 0xe5, 0x19, + 0x0b, 0xd4, 0xba, 0x41, 0xea, 0x9a, 0xad, 0xcc, 0x94, 0x24, + 0x6e, 0x9c, 0x8f, 0xd1, 0x69, 0x6b, 0x4a, 0x50, 0x92, 0xba, + 0x73, 0x41, 0xb1, 0xd1, 0x82, 0x10, 0xbb, 0xcf, 0x3c, 0x4b, + 0xdf, 0x49, 0xdc, 0xdf, 0xd3, 0xbb, 0xa6, 0xac, 0x63, 0xbc, + 0x88, 0x6a, 0x4f, 0x3b, 0xfa, 0xd4, 0xdd, 0xd4, 0x3c, 0x3a, + 0xe5, 0x68, 0xd7, 0x86, 0xbd, 0xcd, 0xd3, 0x6d, 0xa8, 0x22, + 0xca, 0x71, 0xd6, 0xd0, 0xa7, 0xa7, 0x75, 0xd2, 0x70, 0xd4, + 0xb4, 0x27, 0x78, 0x2b, 0xcd, 0x16, 0x10, 0x81, 0xb1, 0x59, + 0xfe, 0xe4, 0x1b, 0x62, 0xd1, 0xcf, 0x63, 0x7c, 0x72, 0x78, + 0xc2, 0x96, 0xaf, 0x88, 0x76, 0x28, 0x0a, 0x47, 0xeb, 0xa8, + 0xd9, 0xd1, 0xef, 0xea, 0x01, 0x20, 0x15, 0x63, 0x89, 0xb4, + 0xe7, 0x99, 0xa0, 0x3b, 0x2f, 0xdf, 0x99, 0x0b, 0xc3, 0xef, + 0xa6, 0xf3, 0xe0, 0x90, 0xc9, 0x82, 0x4c, 0x3e, 0x51, 0xe9, + 0x2c, 0x86, 0x7d, 0x31, 0x7e, 0x8f, 0x5d, 0x7a, 0x24, 0xff, + 0x65, 0xa9, 0xb6, 0xbc, 0x18, 0xc8, 0x28, 0x4c, 0x8d, 0xda, + 0xc7, 0x98, 0x6a, 0x54, 0xad, 0x22, 0x19, 0xca, 0x3d, 0x4d, + 0x88, 0xcc, 0x4e, 0x5c, 0x2a, 0xef, 0xd0, 0x60, 0x3c, 0xe3, + 0x49, 0xd2, 0xf6, 0x59, 0x38, 0x25, 0xed, 0x31, 0x52, 0x18, + 0xb4, 0x31, 0x31, 0x43, 0x8f, 0x85, 0x7d, 0x59, 0xa8, 0xd2, + 0x26, 0x4c, 0xa0, 0xfb, 0xf8, 0xdb, 0x6a, 0x12, 0xad, 0x40, + 0x73, 0xb1, 0x5d, 0x61, 0xf5, 0x49, 0x65, 0x7b, 0x44, 0x30, + 0x49, 0x7a, 0xd7, 0xe9, 0xce, 0x34, 0x9c, 0x64, 0x6e, 0x31, + 0xae, 0x48, 0xad, 0x4c, 0x69, 0xc4, 0xd9, 0xf8, 0x2a, 0xb0, + 0x7e, 0xb3, 0xba, 0xec, 0xea, 0x2b, 0x49, 0x09, 0x21, 0x53, + 0x63, 0xb7, 0xc6, 0xd6, 0x80, 0x9c, 0x77, 0x27, 0xe9, 0xf6, + 0xc7, 0x06, 0x2c, 0x8e, 0xc1, 0xb8, 0x31, 0x15, 0xa9, 0x87, + 0x13, 0xfd, 0xfd, 0x32, 0x18, 0xdd, 0x5c, 0xba, 0xf3, 0x70, + 0x94, 0x09, 0x9d, 0xb6, 0xbc, 0x2c, 0x91, 0xef, 0x42, 0xb7, + 0x13, 0x25, 0x90, 0x77, 0x10, 0xdd, 0x80, 0xa9, 0xd9, 0xab, + 0xef, 0xcf, 0xbe, 0x75, 0x93, 0xe2, 0xbc, 0xe7, 0x26, 0xdf, + 0x77, 0x88, 0xe0, 0x90, 0xc0, 0x2d, 0x20, 0xc9, 0x8c, 0xfa, + 0x82, 0x91, 0x57, 0xfb, 0xb1, 0xec, 0xdf, 0x2b, 0x2f, 0x9b, + 0x6a, 0x23, 0xa0, 0x3e, 0x2a, 0xa3, 0x39, 0x8c, 0xea, 0x09, + 0x06, 0x03, 0x7b, 0xa8, 0xe7, 0x77, 0x32, 0x21, 0x1a, 0x29, + 0xcd, 0x22, 0x60, 0x9b, 0xc0, 0xfe, 0xc2, 0xf3, 0x9c, 0x83, + 0x56, 0x8f, 0xf0, 0x22, 0xad, 0xfd, 0xe3, 0xa9, 0xe3, 0xc5, + 0xbf, 0xd1, 0xf3, 0xbd, 0xc6, 0x43, 0xc3, 0x84, 0xf2, 0x46, + 0x91, 0x5b, 0x37, 0x43, 0xb9, 0xcf, 0xe4, 0x47, 0x7a, 0x5a, + 0xfd, 0xd2, 0xc0, 0xb6, 0x7e, 0x99, 0xea, 0x15, 0x1b, 0x31, + 0x3c, 0x14, 0x6b, 0xbf, 0x26, 0x4f, 0xfa, 0x38, 0x39, 0xef, + 0x75, 0x4c, 0xda, 0x4c, 0x4f, 0x00, 0xef, 0x0f, 0xc6, 0x3b, + 0x5b, 0x4c, 0xf1, 0x1b, 0x35, 0x92, 0xb9, 0x74, 0x9e, 0x0f, + 0x16, 0x2a, 0x2b, 0x3c, 0xa0, 0x80, 0xf0, 0xe5, 0x56, 0xaa, + 0xdb, 0x0e, 0x4f, 0xfc, 0x5f, 0xb2, 0xd1, 0x0b, 0xe2, 0x04, + 0x1e, 0xe8, 0x6f, 0x4f, 0x81, 0xdb, 0xc7, 0x1a, 0x0c, 0xb0, + 0x00, 0xed, 0x8a, 0x7b, 0x1d, 0x44, 0xde, 0x30, 0xfa, 0xb6, + 0x88, 0x3b, 0x73, 0x81, 0xb3, 0x57, 0x31, 0x38, 0x0e, 0x13, + 0x77, 0x9e, 0x5a, 0x4d, 0xa1, 0x93, 0x73, 0x30, 0x0d, 0x44, + 0x56, 0x97, 0x88, 0xbf, 0xc4, 0x36, 0xe9, 0xec, 0xe2, 0x58, + 0x11, 0x39, 0x33, 0x71, 0x6b, 0xd4, 0xb7, 0x4a, 0x9a, 0x2c, + 0xc0, 0xac, 0x88, 0xeb, 0x08, 0x8c, 0x43, 0x48, 0xa2, 0xba, + 0xfa, 0x98, 0x95, 0x92, 0x2d, 0xa2, 0xee, 0x72, 0xb3, 0x7e, + 0xd9, 0x11, 0x1a, 0xa3, 0x41, 0xc4, 0x65, 0x19, 0x1d, 0xdb, + 0x92, 0xf4, 0x3e, 0xf4, 0xaa, 0x49, 0xad, 0x77, 0xc6, 0x03, + 0xdd, 0x19, 0x7a, 0x8d, 0x62, 0x09, 0x19, 0xd7, 0xf7, 0xd3, + 0x84, 0xf1, 0xcb, 0x45, 0x54, 0xd1, 0x74, 0x1e, 0xf8, 0xe6, + 0xa4, 0xfd, 0xaa, 0x30, 0xf8, 0xf9, 0xe1, 0x2b, 0xcf, 0x65, + 0x22, 0xf9, 0x73, 0xcf, 0x5d, 0xe3, 0xde, 0x93, 0x94, 0x84, + 0x8f, 0xe1, 0x66, 0x99, 0x6a, 0x71, 0x76, 0xae, 0xdb, 0x16, + 0x2b, 0x73, 0xab, 0x4e, 0x61, 0x08, 0xa0, 0xdc, 0x3f, 0xd4, + 0xe3, 0xac, 0x89, 0x7a, 0x31, 0xc1, 0xb9, 0x20, 0x92, 0x10, + 0x58, 0x1b, 0x87, 0xfd, 0xe3, 0x7c, 0x42, 0xc8, 0x26, 0x06, + 0x50, 0xce, 0xbb, 0x00, 0x0b, 0x9f, 0x09, 0xdc, 0xac, 0x31, + 0xe0, 0xcd, 0xa6, 0xee, 0x23, 0xef, 0x64, 0x87, 0x65, 0x5f, + 0xfb, 0x5f, 0x6c, 0x29, 0x4a, 0xf9, 0xd3, 0xaf, 0x4e, 0xaa, + 0x39, 0x30, 0x82, 0x05, 0xc6, 0x1c, 0x1e, 0x83, 0x8f, 0xe4, + 0xf7, 0x1c, 0xca, 0x3b, 0x03, 0x01, 0x80, 0xe4, 0x6a, 0x84, + 0x71, 0xd4, 0xe9, 0xa6, 0xba, 0x72, 0x89, 0x69, 0xfa, 0x56, + 0x6d, 0x26, 0xe3, 0x1d, 0xfa, 0x91, 0x8f, 0x4c, 0xcc, 0x50, + 0x74, 0x75, 0x2f, 0xe3, 0x97, 0x16, 0x07, 0x78, 0x40, 0xde, + 0x58, 0x22, 0xca, 0x41, 0xde, 0xb9, 0x92, 0x56, 0x55, 0x89, + 0x85, 0x20, 0x44, 0x5a, 0xd0, 0xfc, 0x88, 0x4e, 0x49, 0x81, + 0x32, 0xcf, 0x44, 0xb6, 0xee, 0x58, 0x0e, 0x22, 0xf8, 0x8f, + 0x05, 0x2a, 0x78, 0x30, 0x34, 0x11, 0xb0, 0x8f, 0x21, 0x10, + 0xb7, 0xe2, 0x80, 0xa2, 0xe0, 0x69, 0xbc, 0x29, 0xe3, 0x48, + 0x08, 0xa6, 0xdc, 0xbc, 0x68, 0xd7, 0xd7, 0x84, 0x23, 0x3f, + 0xb0, 0x0a, 0x69, 0xa1, 0x87, 0x13, 0x29, 0x0d, 0x71, 0x3d, + 0xad, 0xad, 0xf0, 0x5e, 0x53, 0x04, 0x03, 0x9e, 0x4b, 0xb2, + 0x24, 0xc2, 0x82, 0x8c, 0xef, 0x4c, 0x70, 0xcd, 0x58, 0xb3, + 0x19, 0xa4, 0xe8, 0x0e, 0xc0, 0xfd, 0x57, 0x2b, 0x65, 0xee, + 0xa5, 0x43, 0x02, 0xf2, 0xbe, 0xe7, 0x66, 0xc9, 0xb5, 0xfd, + 0x70, 0xc0, 0x93, 0x9b, 0xe8, 0x60, 0x74, 0xd4, 0xcc, 0xa5, + 0xa6, 0xa2, 0x66, 0x35, 0xdc, 0x74, 0xf3, 0x02, 0x16, 0x74, + 0x9a, 0x91, 0x0a, 0x3d, 0xa4, 0x8b, 0x98, 0xd1, 0xfd, 0x29, + 0x34, 0xea, 0x52, 0x89, 0x16, 0x62, 0xdd, 0xed, 0xb5, 0x8b, + 0xed, 0xe4, 0x03, 0xd9 + }; + + static const uint8_t static_keys_b[0x70 * 0x20] = { + 0x76, 0x65, 0x9d, 0xe4, 0xf7, 0x6c, 0x45, 0x1f, 0x73, 0x42, + 0x47, 0xc3, 0x92, 0x32, 0xf4, 0x38, 0x6f, 0x28, 0xcf, 0xfa, + 0x41, 0x84, 0xbe, 0x1b, 0x5a, 0x23, 0x99, 0xfa, 0xcd, 0x74, + 0xf0, 0x3b, 0x43, 0xc9, 0xd1, 0x30, 0x66, 0x77, 0x5e, 0xac, + 0x39, 0x8e, 0x8a, 0x6c, 0x5c, 0xfe, 0xdd, 0x80, 0xf3, 0x03, + 0x04, 0x30, 0x84, 0x9d, 0x12, 0xee, 0x4a, 0xe3, 0x0f, 0x5e, + 0x5e, 0x97, 0xd0, 0xf9, 0x1b, 0x57, 0x05, 0x74, 0x03, 0x5a, + 0x5d, 0x41, 0xda, 0x6e, 0xfd, 0x4b, 0x1e, 0xc4, 0x4b, 0x76, + 0xe4, 0xd3, 0x39, 0xeb, 0x3c, 0x2c, 0xae, 0x27, 0xe2, 0x98, + 0xe4, 0x08, 0xa3, 0xbe, 0xb0, 0x31, 0x69, 0x14, 0xa3, 0x6c, + 0xdf, 0xfc, 0x1f, 0x56, 0x0d, 0xfe, 0x55, 0x12, 0x97, 0x5e, + 0xad, 0x3d, 0x9b, 0xee, 0xb5, 0xad, 0xa3, 0x56, 0x85, 0xc3, + 0xbd, 0x9b, 0xef, 0xac, 0x55, 0x98, 0x1f, 0xaf, 0xb8, 0x0b, + 0xae, 0xed, 0xf3, 0x87, 0x34, 0xc9, 0x5b, 0x69, 0xf0, 0xed, + 0x4f, 0x03, 0x40, 0xa5, 0x71, 0x24, 0xa2, 0x23, 0x93, 0x52, + 0xe9, 0x87, 0xc4, 0x79, 0x4f, 0xe9, 0x20, 0xbc, 0x04, 0x58, + 0x70, 0x96, 0xb1, 0xd7, 0x37, 0xc4, 0x29, 0x4d, 0x3d, 0x52, + 0xd3, 0xcf, 0x7c, 0x08, 0xe9, 0x82, 0xc6, 0x99, 0xf5, 0xdb, + 0x60, 0x11, 0x9b, 0x9d, 0x25, 0x86, 0x08, 0xb3, 0x77, 0x27, + 0xa8, 0x2c, 0xf9, 0x28, 0x2f, 0x2b, 0x70, 0x6c, 0x4b, 0xbb, + 0x1e, 0x49, 0x3e, 0xd6, 0x69, 0xd8, 0xe8, 0x09, 0xf4, 0x9c, + 0x09, 0x32, 0xdf, 0xdd, 0xe1, 0x0b, 0x41, 0x0e, 0x26, 0x3e, + 0x53, 0xcc, 0x7a, 0xd1, 0x15, 0x16, 0xfb, 0xc3, 0x09, 0xd3, + 0xad, 0xa4, 0xea, 0xa3, 0x4a, 0xbe, 0xf2, 0x88, 0x9a, 0x34, + 0x7b, 0x09, 0x41, 0x44, 0xf1, 0x5e, 0x3c, 0x4f, 0x0e, 0x9f, + 0x5a, 0x95, 0x57, 0x7a, 0xfe, 0xbe, 0xc8, 0x24, 0x1f, 0x98, + 0x85, 0x1e, 0x25, 0x74, 0x90, 0xdd, 0x5a, 0xd1, 0x7c, 0x02, + 0xbe, 0x63, 0xe5, 0xc7, 0xa2, 0x0b, 0x26, 0xdf, 0x20, 0x84, + 0x61, 0xe3, 0xff, 0x2c, 0x69, 0x32, 0x91, 0x62, 0xf8, 0x11, + 0x7c, 0xf2, 0x1e, 0xe5, 0x1e, 0xc1, 0xb2, 0x2a, 0x84, 0x8e, + 0x3a, 0x78, 0xf6, 0xf6, 0x76, 0x76, 0x4e, 0x34, 0x4f, 0x24, + 0xf0, 0x8c, 0x34, 0xaf, 0x95, 0x7a, 0x35, 0x26, 0x5e, 0x28, + 0xe3, 0x2c, 0x66, 0xf9, 0x7f, 0x35, 0xfc, 0xad, 0xfe, 0x6e, + 0x4b, 0xe1, 0x5c, 0x48, 0xec, 0x1a, 0xba, 0xbd, 0xac, 0x73, + 0x7a, 0xe8, 0xbc, 0xad, 0xba, 0x5e, 0xa6, 0xf0, 0xb8, 0x5a, + 0x51, 0x2a, 0x97, 0xe4, 0x34, 0x8a, 0x3b, 0x64, 0x61, 0x97, + 0x57, 0x59, 0x29, 0x87, 0x76, 0x80, 0x78, 0x05, 0x91, 0xc0, + 0xa5, 0x5e, 0x7b, 0x5a, 0xa5, 0x7b, 0x2f, 0x8d, 0x07, 0x7d, + 0xfa, 0x75, 0x32, 0xe8, 0x48, 0x0c, 0x68, 0xbf, 0x70, 0xb3, + 0x79, 0x88, 0xc0, 0xbd, 0xbc, 0x49, 0x9a, 0x9a, 0x07, 0xb8, + 0xa3, 0xc2, 0xb4, 0x1d, 0xca, 0x24, 0x90, 0xe8, 0x2f, 0xe8, + 0x9f, 0x28, 0xba, 0x40, 0x17, 0x50, 0x56, 0xcf, 0x4e, 0xc8, + 0x82, 0xcb, 0x77, 0xf1, 0x74, 0x8d, 0xef, 0x0b, 0x4c, 0x1f, + 0x3d, 0x4d, 0xd2, 0x4e, 0x66, 0x2f, 0x13, 0xe7, 0x8a, 0xb6, + 0xea, 0xd1, 0xd7, 0x36, 0xf3, 0x51, 0x65, 0x07, 0xc1, 0x88, + 0x7d, 0xae, 0xf4, 0xb8, 0x89, 0xb5, 0xce, 0xdd, 0x27, 0xbe, + 0x6f, 0x6c, 0x81, 0x8f, 0x56, 0x02, 0x0d, 0x49, 0xe4, 0x3f, + 0x60, 0x93, 0x55, 0xa3, 0x68, 0x75, 0x5d, 0xc5, 0x5a, 0x09, + 0x90, 0xdc, 0x8f, 0xaa, 0x9f, 0x47, 0xf6, 0xa9, 0xad, 0xdb, + 0x5b, 0xe2, 0x64, 0xce, 0xc1, 0x26, 0xeb, 0xeb, 0xa0, 0x03, + 0x23, 0x61, 0x14, 0x9e, 0x72, 0x48, 0xc2, 0x10, 0x3d, 0x73, + 0xc3, 0xc9, 0x22, 0x01, 0x68, 0x2c, 0x3c, 0x98, 0xa5, 0x85, + 0x0d, 0xa4, 0xec, 0xc6, 0xfc, 0x7d, 0xff, 0x2c, 0xae, 0x60, + 0xc4, 0xb0, 0x71, 0xb9, 0xbc, 0xdb, 0x29, 0xc6, 0x78, 0x0b, + 0xf6, 0x82, 0x38, 0xed, 0x35, 0xb7, 0x92, 0x2f, 0xeb, 0xa9, + 0xe7, 0xc3, 0x1a, 0xa2, 0xae, 0x44, 0x51, 0x71, 0x6e, 0x8c, + 0x21, 0x9f, 0x9c, 0x5d, 0x98, 0x72, 0xa3, 0x2e, 0x74, 0x49, + 0x70, 0xaf, 0x85, 0x7b, 0x14, 0x66, 0x56, 0x99, 0x89, 0x07, + 0xc4, 0xa9, 0xc2, 0xc2, 0xb3, 0x39, 0xa6, 0xf5, 0x5b, 0x3f, + 0x30, 0xcc, 0x2d, 0x03, 0x22, 0xb4, 0x2a, 0x27, 0x1a, 0x46, + 0xbc, 0xe5, 0xf6, 0x19, 0x34, 0xc1, 0x06, 0x6f, 0x28, 0x84, + 0xe1, 0xe3, 0xb0, 0x21, 0x21, 0x84, 0x34, 0x33, 0x8d, 0x01, + 0x26, 0x44, 0x5f, 0xa3, 0x56, 0x19, 0x46, 0xc1, 0x78, 0x29, + 0x38, 0x0b, 0x9f, 0xe1, 0xf1, 0x2b, 0xfc, 0x01, 0x91, 0x71, + 0x1c, 0xa5, 0x9c, 0xb6, 0xe1, 0x5e, 0xfa, 0x26, 0x56, 0x3f, + 0xa8, 0xb2, 0xd1, 0xe4, 0xf3, 0x69, 0x08, 0x36, 0xac, 0xd6, + 0x67, 0xb6, 0xe6, 0xb8, 0xc7, 0xa6, 0x7a, 0x10, 0x49, 0xe7, + 0xba, 0x6f, 0xbf, 0xe8, 0x25, 0xaf, 0xc2, 0xdf, 0xf3, 0xa1, + 0x76, 0xf4, 0x2b, 0x8c, 0x6f, 0x01, 0xce, 0x96, 0x30, 0xd2, + 0x2d, 0xf8, 0x6c, 0xad, 0xed, 0x1e, 0xe5, 0x7a, 0xdf, 0x37, + 0xe6, 0xff, 0xed, 0x9d, 0x5f, 0xa9, 0xfb, 0xf1, 0xbc, 0xc7, + 0x47, 0x5a, 0x6f, 0x77, 0x83, 0x18, 0x0e, 0xba, 0x18, 0x2b, + 0x38, 0xb4, 0x36, 0x32, 0x36, 0xdc, 0x98, 0xec, 0x16, 0xa1, + 0x68, 0x42, 0x95, 0xee, 0xad, 0x43, 0x4c, 0x3d, 0x31, 0xcf, + 0xdb, 0x57, 0xae, 0x0f, 0x78, 0x52, 0xd8, 0xa6, 0x47, 0x4b, + 0xba, 0x94, 0xc2, 0xd2, 0x97, 0x56, 0x2b, 0xb0, 0xbd, 0x43, + 0x30, 0x05, 0x4b, 0x30, 0x7b, 0x8b, 0xe4, 0xee, 0x61, 0xc4, + 0xcd, 0xcb, 0x08, 0xb1, 0x16, 0x2e, 0xa3, 0xe4, 0x20, 0x0e, + 0xd5, 0x02, 0x17, 0x81, 0xba, 0x43, 0xf7, 0x02, 0x7a, 0x0e, + 0x77, 0x15, 0x45, 0x03, 0xaa, 0x84, 0x88, 0x56, 0xb1, 0xee, + 0x3a, 0x1f, 0xe6, 0x28, 0xfd, 0x9f, 0x05, 0x81, 0x8d, 0xbf, + 0x53, 0xa1, 0x5b, 0xbd, 0x9c, 0x79, 0x53, 0x28, 0x73, 0xba, + 0x0d, 0x72, 0xe7, 0x14, 0xed, 0x5d, 0xb7, 0x95, 0x09, 0xa0, + 0xbf, 0xef, 0x75, 0xa1, 0x20, 0xa4, 0x2d, 0x16, 0xa6, 0x58, + 0x61, 0x93, 0x3a, 0x62, 0x40, 0xca, 0x4e, 0xef, 0xe4, 0x31, + 0x18, 0xd1, 0x39, 0x35, 0x7c, 0x78, 0xe3, 0x6c, 0x76, 0x8a, + 0x37, 0xdd, 0xc3, 0x8e, 0x60, 0xe2, 0x0d, 0x67, 0xfc, 0xe7, + 0x37, 0x88, 0x48, 0xb6, 0xe4, 0x4b, 0x87, 0xe6, 0x04, 0x8c, + 0x06, 0xd8, 0xc7, 0x4e, 0x9a, 0x97, 0x9d, 0x9d, 0xa1, 0xfa, + 0x11, 0x27, 0x8c, 0x34, 0xe7, 0x02, 0x55, 0x0f, 0x6e, 0xc6, + 0xcd, 0x6b, 0xc4, 0xf0, 0xa1, 0x05, 0x6b, 0x3f, 0xc4, 0xc9, + 0x47, 0x95, 0x85, 0x1f, 0x80, 0x6a, 0x23, 0xe7, 0x24, 0x9f, + 0xc3, 0xd0, 0x9d, 0x17, 0xea, 0x2f, 0xfa, 0xfa, 0xe4, 0xa6, + 0x88, 0x9a, 0x57, 0x0c, 0x5b, 0xfe, 0xb4, 0x67, 0x3e, 0xf0, + 0x0a, 0x58, 0xa0, 0xc8, 0xc7, 0x16, 0xd6, 0x0b, 0x41, 0x9e, + 0xa9, 0xde, 0xbf, 0x17, 0x49, 0x08, 0x82, 0xc4, 0x4e, 0x56, + 0x53, 0xb0, 0x4e, 0x23, 0x1d, 0xa8, 0x07, 0xde, 0x98, 0xf8, + 0xe9, 0xec, 0x45, 0x3b, 0x50, 0xf6, 0xb6, 0xa3, 0xdc, 0xfa, + 0xa1, 0x86, 0xd3, 0xfa, 0xda, 0xb6, 0x1d, 0x27, 0xed, 0x3d, + 0x17, 0xc9, 0xcc, 0xf6, 0x2f, 0x7d, 0xea, 0x3b, 0x3d, 0x58, + 0xb7, 0xf0, 0x4a, 0xae, 0xf9, 0x2f, 0xa0, 0x80, 0xe9, 0xde, + 0x2e, 0x30, 0x3c, 0xd6, 0x46, 0xca, 0x50, 0x25, 0xf7, 0xa2, + 0x66, 0xec, 0xa5, 0x6e, 0x06, 0x6e, 0x00, 0x3e, 0x08, 0x6c, + 0xe6, 0x3b, 0xfb, 0xc8, 0xa7, 0xd0, 0x1e, 0xc8, 0x25, 0x24, + 0x11, 0x0b, 0x39, 0x0f, 0x70, 0xd9, 0xf8, 0xff, 0x54, 0x54, + 0x9d, 0x02, 0xab, 0x4c, 0x8c, 0x90, 0x94, 0xe5, 0x0e, 0xd5, + 0x62, 0x78, 0xab, 0xa5, 0x9c, 0x11, 0x1c, 0x70, 0x07, 0x9b, + 0x2a, 0xe4, 0xfb, 0xed, 0xfb, 0xcd, 0x92, 0x0d, 0xbc, 0x21, + 0x25, 0x33, 0x0b, 0xbf, 0xf3, 0x18, 0x93, 0x73, 0xed, 0xf3, + 0x88, 0x3b, 0x43, 0x97, 0xce, 0x19, 0x25, 0xf5, 0xbb, 0x71, + 0x26, 0x98, 0x2c, 0xd6, 0xff, 0x32, 0x4f, 0x75, 0xcc, 0x92, + 0x4e, 0xe3, 0xbe, 0xb8, 0xbf, 0x33, 0x89, 0xe5, 0x09, 0x4c, + 0x41, 0x8c, 0xb0, 0x51, 0x74, 0x32, 0xea, 0x96, 0xce, 0x70, + 0x1c, 0x5c, 0x26, 0x34, 0x66, 0x3a, 0x3a, 0xe8, 0x92, 0x4e, + 0xd2, 0x61, 0x70, 0x12, 0x3c, 0x33, 0x9d, 0x09, 0x57, 0x23, + 0x48, 0x81, 0x29, 0x7f, 0xc9, 0x4d, 0x06, 0xe8, 0xc5, 0x6e, + 0x50, 0x7c, 0x8f, 0xfa, 0xf0, 0xb4, 0xe6, 0x9c, 0x7d, 0x5e, + 0x09, 0x36, 0xb3, 0x24, 0xc4, 0xf8, 0xe3, 0x19, 0xa8, 0x65, + 0x3f, 0x2a, 0x84, 0x98, 0x79, 0x18, 0x58, 0x26, 0x29, 0x5e, + 0xbc, 0x3c, 0x7e, 0x80, 0xaa, 0x04, 0x43, 0x1b, 0xbd, 0x36, + 0xef, 0x5c, 0xc6, 0x78, 0xfb, 0xa6, 0xfd, 0x26, 0x6a, 0xa4, + 0xb6, 0x2e, 0x92, 0xb7, 0x7a, 0x02, 0xa7, 0xc8, 0xb0, 0x47, + 0xa8, 0x6e, 0x6a, 0x53, 0x15, 0x81, 0x7d, 0x1c, 0xb0, 0x55, + 0xbe, 0xa9, 0x11, 0x1e, 0xd0, 0xd8, 0x99, 0x37, 0xae, 0x35, + 0xfa, 0xe4, 0x0b, 0x4c, 0x52, 0x0c, 0x12, 0x3a, 0x5f, 0x09, + 0x4e, 0x21, 0xc6, 0x0d, 0x56, 0xe4, 0x23, 0xd2, 0x5e, 0x86, + 0x7f, 0x04, 0xb0, 0x1c, 0xeb, 0x9f, 0x50, 0x17, 0xcc, 0x8e, + 0xf9, 0x8f, 0x00, 0x91, 0xee, 0xa7, 0xa4, 0x91, 0x59, 0xb7, + 0x11, 0x9e, 0x87, 0x40, 0xe2, 0x41, 0x08, 0x0f, 0xec, 0x40, + 0xbc, 0x8c, 0x30, 0x14, 0xcc, 0x97, 0xc9, 0xf0, 0x50, 0x7b, + 0x5c, 0x18, 0xe2, 0x1b, 0x02, 0x7f, 0xda, 0xc0, 0xe6, 0x23, + 0x4b, 0x48, 0xbb, 0xe8, 0x01, 0xe9, 0xd4, 0xb8, 0x52, 0xfa, + 0x36, 0x99, 0xdd, 0x03, 0x8d, 0x21, 0xd3, 0x16, 0x17, 0x2c, + 0x25, 0x20, 0x70, 0x92, 0xd5, 0x57, 0xcb, 0xff, 0x70, 0x16, + 0x33, 0x18, 0xf3, 0x31, 0x1a, 0xb0, 0x07, 0x27, 0x82, 0xc5, + 0x13, 0x86, 0x3d, 0xb5, 0x22, 0xfb, 0x7d, 0x2a, 0x4d, 0x45, + 0xaa, 0x2f, 0x46, 0x67, 0x1e, 0x9f, 0xc4, 0x8b, 0x3a, 0xb8, + 0x8c, 0x56, 0x3c, 0xa4, 0xfe, 0xe7, 0x93, 0xb2, 0xed, 0xc8, + 0x19, 0x3c, 0xc0, 0x5d, 0x38, 0xb0, 0xa2, 0x54, 0xe8, 0x71, + 0xd1, 0x69, 0xc7, 0xb8, 0xdc, 0x33, 0x0c, 0x3b, 0x8f, 0xf4, + 0x37, 0x23, 0x3d, 0x1e, 0x7b, 0x50, 0xc5, 0x4c, 0x3a, 0x6a, + 0x8d, 0xa8, 0x2b, 0x3d, 0x8c, 0x63, 0x4e, 0x52, 0x79, 0xea, + 0x7f, 0xa2, 0x0c, 0xc0, 0xdc, 0xba, 0x60, 0x04, 0x86, 0xa5, + 0xd6, 0x2b, 0xab, 0x2a, 0x17, 0xbe, 0x95, 0x11, 0x2d, 0x14, + 0x4e, 0xc1, 0x42, 0xa3, 0x8e, 0xaf, 0x57, 0x4d, 0x84, 0xd9, + 0x3c, 0x91, 0xb9, 0x45, 0x09, 0x6a, 0xf5, 0xb3, 0x24, 0x4a, + 0x2d, 0x69, 0x46, 0x51, 0x65, 0x9a, 0x37, 0x11, 0x7d, 0xde, + 0x9c, 0x7c, 0x11, 0xaf, 0x81, 0xfa, 0xdf, 0x1e, 0x5d, 0xff, + 0xb2, 0x64, 0x33, 0x75, 0x23, 0x7f, 0x99, 0xc2, 0xa6, 0xb8, + 0x30, 0xdf, 0xd2, 0xb6, 0x5a, 0x35, 0x6b, 0xc5, 0x28, 0xb0, + 0x60, 0x1a, 0x85, 0x59, 0x2e, 0x2b, 0x8b, 0x8f, 0x9a, 0x4c, + 0xd2, 0x9b, 0x90, 0x1e, 0x95, 0x5a, 0xf3, 0xac, 0x34, 0x78, + 0x8c, 0xeb, 0x67, 0x09, 0x6b, 0x95, 0x73, 0x5e, 0x54, 0x1f, + 0x05, 0xd6, 0xe4, 0xf4, 0x3b, 0x4d, 0x93, 0x13, 0x8a, 0xa2, + 0x36, 0x62, 0xb9, 0x76, 0xdc, 0x77, 0xf7, 0x10, 0xf6, 0x73, + 0xb7, 0x49, 0x90, 0x53, 0x9a, 0xbe, 0x96, 0x9d, 0x4c, 0xd4, + 0xf5, 0x09, 0x15, 0x88, 0xe8, 0xc7, 0xbd, 0x04, 0x1e, 0xf8, + 0x70, 0x88, 0x7d, 0xf9, 0x2c, 0xf4, 0x80, 0x5c, 0x6f, 0x55, + 0x73, 0xf2, 0xa0, 0x90, 0xb4, 0xb4, 0xb9, 0x80, 0x49, 0x3a, + 0xc5, 0xda, 0x84, 0x8c, 0x26, 0x84, 0x90, 0xc1, 0x2b, 0xa6, + 0xac, 0x48, 0x2d, 0x37, 0x61, 0x27, 0xd2, 0x18, 0xb8, 0x51, + 0x28, 0x0b, 0x13, 0xbb, 0x35, 0x58, 0xe6, 0xf0, 0x24, 0x18, + 0x28, 0x42, 0x6d, 0xdd, 0xba, 0xe8, 0x64, 0xf2, 0xff, 0x47, + 0x27, 0x59, 0x16, 0x55, 0xcc, 0x5b, 0x54, 0xa3, 0xe2, 0xfb, + 0xef, 0x14, 0x68, 0x8d, 0xbf, 0x2e, 0x9a, 0xbc, 0xfa, 0xb8, + 0x8e, 0x5e, 0x37, 0x8a, 0x1b, 0x67, 0x09, 0xe8, 0x0b, 0xed, + 0x44, 0x71, 0x16, 0x05, 0xbc, 0x5b, 0x2a, 0xf8, 0x8a, 0xdd, + 0xd9, 0x74, 0x53, 0x73, 0xb0, 0xd9, 0xb9, 0xfd, 0xd6, 0x67, + 0x52, 0x7e, 0x2c, 0x50, 0x36, 0xd0, 0x3b, 0xf7, 0x1f, 0xd8, + 0x4a, 0x06, 0x11, 0xf3, 0x21, 0x1f, 0x6e, 0x8f, 0x24, 0x44, + 0xb8, 0xa1, 0xba, 0x0a, 0xbb, 0x6c, 0x18, 0x02, 0x8e, 0xe7, + 0x5b, 0xed, 0xaa, 0x39, 0xbb, 0xb5, 0x99, 0x00, 0xd9, 0x62, + 0x26, 0x5f, 0x26, 0x3e, 0x8e, 0x49, 0x11, 0xd4, 0x2e, 0x70, + 0x5e, 0x79, 0x08, 0x63, 0xfb, 0x8d, 0x70, 0x8f, 0x4f, 0x1d, + 0x4f, 0x33, 0x72, 0xcd, 0xb1, 0xbd, 0x20, 0x4c, 0x74, 0x7f, + 0xde, 0x54, 0xe3, 0x1e, 0xb1, 0x0d, 0xb1, 0xeb, 0x5c, 0x63, + 0xd6, 0xc9, 0xaf, 0x82, 0xa6, 0xc5, 0x19, 0xe7, 0x96, 0x2f, + 0xaf, 0x19, 0x79, 0x4a, 0xe4, 0x78, 0xd0, 0xb3, 0xfc, 0xff, + 0xd7, 0x8f, 0x35, 0x93, 0x41, 0x2d, 0x59, 0xf2, 0xd8, 0xcc, + 0x76, 0xb8, 0x3a, 0xf7, 0xdf, 0x1c, 0xa8, 0x85, 0xd5, 0xf8, + 0x54, 0x63, 0x75, 0x36, 0xea, 0x30, 0x5a, 0x13, 0x74, 0xf9, + 0x6d, 0x55, 0x27, 0x04, 0x0b, 0xa0, 0xa0, 0x6d, 0x9e, 0x3a, + 0x93, 0xbf, 0x4e, 0x92, 0x28, 0x85, 0xe4, 0xcf, 0xc5, 0x06, + 0xa7, 0x17, 0x5a, 0xec, 0xc2, 0x60, 0x6a, 0xab, 0x1b, 0x50, + 0xc9, 0x0b, 0x84, 0x9a, 0x82, 0x45, 0x1e, 0x29, 0xcc, 0x85, + 0x5a, 0xa8, 0xd4, 0x90, 0xfb, 0xa7, 0x2f, 0x89, 0xa7, 0x80, + 0xd0, 0x69, 0xb6, 0xca, 0xe0, 0x00, 0x4e, 0xe8, 0xea, 0x12, + 0x74, 0x85, 0xc8, 0x35, 0xea, 0x1d, 0x23, 0x75, 0x97, 0xcb, + 0x1d, 0x94, 0x6f, 0x2a, 0xa9, 0x7a, 0x32, 0xc5, 0x92, 0xf0, + 0x0a, 0x28, 0xbd, 0x77, 0xbc, 0xbe, 0xae, 0xa7, 0xa8, 0x34, + 0x96, 0x26, 0xaf, 0x83, 0x2a, 0x8e, 0xe9, 0xda, 0xad, 0xb2, + 0x52, 0x94, 0x74, 0x69, 0x70, 0x19, 0xc4, 0xc8, 0x36, 0xf3, + 0x0f, 0x32, 0x0f, 0x6f, 0x2b, 0x75, 0xac, 0x0e, 0x9d, 0x91, + 0x1f, 0x06, 0xba, 0xe3, 0x9c, 0x7f, 0xde, 0x16, 0x3a, 0x3f, + 0xfd, 0x7d, 0x88, 0x61, 0x90, 0xca, 0x98, 0xc1, 0xcf, 0xa5, + 0x50, 0x1f, 0xb3, 0x8c, 0xf9, 0x8c, 0xe9, 0x9f, 0xa3, 0xd3, + 0xd7, 0xce, 0x7f, 0xdf, 0xd2, 0x8e, 0x84, 0x9c, 0x24, 0xc3, + 0x85, 0xb1, 0xc6, 0x94, 0x8f, 0xbb, 0x55, 0x83, 0x8e, 0xa3, + 0xc7, 0xf5, 0x8e, 0x7e, 0xe6, 0x30, 0x13, 0x06, 0x61, 0x9e, + 0x63, 0x24, 0x27, 0x03, 0x01, 0xef, 0xec, 0x6d, 0xb1, 0x56, + 0x86, 0xd9, 0xf3, 0x2e, 0xfc, 0xe2, 0xbb, 0xa5, 0xa7, 0xaa, + 0x9c, 0x06, 0xf3, 0x36, 0x04, 0xae, 0xbd, 0x0f, 0x6f, 0xb9, + 0xc7, 0x42, 0x79, 0xfd, 0xac, 0x8f, 0x1c, 0xcc, 0x01, 0x9f, + 0x45, 0x3a, 0x52, 0xa2, 0x20, 0x31, 0xf6, 0x5d, 0xea, 0x4e, + 0xe7, 0x13, 0x9d, 0x79, 0xe8, 0x81, 0x62, 0xcd, 0xaf, 0x2e, + 0x6b, 0xb5, 0x1b, 0x75, 0xfe, 0x61, 0xf7, 0xcf, 0x4d, 0x90, + 0xdf, 0xe8, 0x56, 0x23, 0x96, 0xe4, 0xab, 0x5d, 0xa5, 0xd8, + 0x2e, 0x9e, 0x0c, 0x30, 0x27, 0xa3, 0x2c, 0x10, 0xda, 0x79, + 0xaf, 0xb9, 0x16, 0x6a, 0x89, 0x33, 0xe7, 0x46, 0xef, 0x43, + 0xe5, 0x5e, 0xb6, 0x38, 0xaa, 0x07, 0xb6, 0x5d, 0xd8, 0x57, + 0x4b, 0x94, 0xbd, 0xd0, 0x73, 0x9c, 0xf9, 0xa9, 0x31, 0x8a, + 0x71, 0xe5, 0xf0, 0xe6, 0xfb, 0x4e, 0xc4, 0xc7, 0x4b, 0xfe, + 0xe2, 0x1e, 0xbc, 0x77, 0xba, 0x3b, 0x2c, 0xa2, 0x71, 0x2e, + 0xf1, 0xd7, 0x33, 0xa2, 0xae, 0x2d, 0x89, 0x6a, 0xcb, 0x63, + 0xed, 0x8d, 0x83, 0x10, 0x96, 0xb4, 0x43, 0xef, 0xc2, 0xe6, + 0x49, 0x13, 0x2f, 0x0a, 0x09, 0xae, 0xca, 0xa8, 0x01, 0xff, + 0xc9, 0x65, 0x87, 0x8d, 0x20, 0x98, 0x5f, 0xfb, 0x25, 0xe0, + 0x7a, 0x3a, 0xcb, 0xf8, 0x48, 0x7e, 0x18, 0xcc, 0x4c, 0x66, + 0xd3, 0x76, 0x10, 0x93, 0xa2, 0x7d, 0x3b, 0x0d, 0x49, 0xca, + 0xa9, 0x18, 0x2a, 0x50, 0xe2, 0xb3, 0xdc, 0x77, 0x3c, 0x23, + 0x84, 0xfe, 0xe7, 0x86, 0x39, 0x7f, 0xc7, 0x18, 0xca, 0xae, + 0x79, 0xfc, 0x44, 0x27, 0xf9, 0xbc, 0xce, 0xdb, 0xda, 0xe9, + 0xd5, 0x83, 0x90, 0xfb, 0x8c, 0x79, 0x4b, 0xc9, 0x1b, 0x6b, + 0x57, 0x0a, 0x88, 0xfc, 0x80, 0x7d, 0x17, 0x10, 0x32, 0x7d, + 0xf5, 0x87, 0xf7, 0x18, 0xd6, 0x7a, 0x60, 0x5c, 0x2b, 0x4a, + 0x19, 0x0a, 0xea, 0x3f, 0xd1, 0x5b, 0x5e, 0x93, 0x38, 0x9f, + 0xc9, 0xfc, 0x6c, 0x67, 0x91, 0xd6, 0x0c, 0x3b, 0x1e, 0xa6, + 0x2d, 0x1a, 0x71, 0x74, 0x57, 0x67, 0x46, 0xa2, 0x93, 0xaf, + 0x9d, 0x85, 0x0e, 0x0b, 0x1d, 0x39, 0x84, 0xe1, 0x7c, 0x8a, + 0x11, 0xed, 0x7b, 0xfe, 0x98, 0xaf, 0x2b, 0x7a, 0xe6, 0xc6, + 0x70, 0xf7, 0xce, 0x13, 0xe6, 0x5a, 0x96, 0x7e, 0x5d, 0x76, + 0x30, 0xfc, 0x22, 0xdc, 0x4e, 0xb2, 0xd5, 0x59, 0x66, 0x54, + 0x70, 0x25, 0x83, 0x1f, 0x16, 0xf0, 0x0a, 0x72, 0xd5, 0xb1, + 0x69, 0x86, 0x13, 0xb8, 0x6c, 0x0f, 0xe0, 0x5a, 0xdd, 0x5e, + 0x26, 0x9a, 0x9e, 0xbc, 0x94, 0xdf, 0xd0, 0x08, 0x4f, 0xc9, + 0x87, 0xf3, 0xd5, 0x6d, 0xad, 0x65, 0xbd, 0x52, 0xd2, 0x10, + 0x71, 0xca, 0x4b, 0xe5, 0x72, 0xcd, 0xae, 0xa7, 0x9c, 0x51, + 0x52, 0x04, 0xe5, 0xcb, 0x80, 0xfa, 0x23, 0x1b, 0x4a, 0x0d, + 0x83, 0x8a, 0xa6, 0x91, 0xef, 0x10, 0x08, 0x05, 0x2a, 0x39, + 0x14, 0x2f, 0xdb, 0x1f, 0x96, 0x8d, 0xe1, 0x58, 0x08, 0xd0, + 0x65, 0x6d, 0x83, 0x8f, 0x71, 0xe0, 0x87, 0x90, 0x96, 0xce, + 0xa4, 0xa0, 0x30, 0xf7, 0x56, 0xd4, 0x88, 0x61, 0x08, 0x61, + 0xda, 0xd1, 0x36, 0x8a, 0x92, 0x3f, 0xb1, 0xd4, 0xd0, 0x6f, + 0x57, 0x9b, 0xb4, 0xe2, 0x96, 0x12, 0xad, 0x93, 0x4b, 0xd6, + 0x59, 0x37, 0x08, 0x4f, 0x7a, 0xc8, 0x7f, 0x37, 0x8e, 0x11, + 0x5f, 0x07, 0xd2, 0x5e, 0xbe, 0x54, 0xcb, 0xa8, 0xc6, 0x2e, + 0xfc, 0x23, 0x7e, 0xab, 0x40, 0x24, 0x19, 0x4c, 0x51, 0x19, + 0x52, 0xcc, 0xc2, 0x70, 0x63, 0xc6, 0x34, 0x1c, 0x97, 0x14, + 0xb1, 0xfe, 0xd3, 0xe6, 0x98, 0xf2, 0xd7, 0x77, 0x5a, 0x69, + 0xc6, 0xf6, 0x0f, 0xb9, 0x62, 0xae, 0x4a, 0xb0, 0x33, 0x3a, + 0x43, 0x16, 0x2b, 0x66, 0xbf, 0xc6, 0x8c, 0x41, 0x8d, 0x0f, + 0x94, 0x79, 0x77, 0x81, 0x01, 0x23, 0xd9, 0x5e, 0x81, 0x74, + 0x1d, 0x87, 0x11, 0x76, 0xc6, 0x0f, 0x40, 0x91, 0x72, 0xe9, + 0x7d, 0x51, 0xb8, 0x72, 0xa9, 0x6f, 0x23, 0x1d, 0x32, 0x33, + 0xde, 0xd8, 0xf7, 0x9c, 0x52, 0xa4, 0x6d, 0x4f, 0x3f, 0x9e, + 0xe4, 0xfa, 0x25, 0x8f, 0x27, 0x78, 0x8d, 0xde, 0x39, 0xa2, + 0xfd, 0xd1, 0x39, 0x01, 0xeb, 0xce, 0xac, 0x60, 0xe4, 0x9f, + 0x69, 0x8b, 0xf8, 0xd1, 0x85, 0x70, 0x74, 0xad, 0x1e, 0x30, + 0x89, 0x9f, 0x84, 0x58, 0xff, 0xd5, 0x84, 0x41, 0xa6, 0x68, + 0x16, 0xc8, 0x07, 0x9b, 0x7a, 0x33, 0x29, 0x05, 0x5c, 0x0e, + 0x08, 0x94, 0x4d, 0x18, 0x80, 0xba, 0x10, 0x82, 0x4e, 0x92, + 0x60, 0xa8, 0xff, 0x1a, 0x0e, 0x46, 0x57, 0x1e, 0x65, 0x67, + 0x25, 0x8d, 0x28, 0xb1, 0xdb, 0x66, 0xca, 0xc0, 0xbc, 0xa9, + 0x90, 0x8a, 0x74, 0x52, 0x97, 0x68, 0x32, 0x34, 0x60, 0xb0, + 0x30, 0x60, 0xd5, 0x89, 0x15, 0x09, 0x1f, 0x95, 0xc5, 0x41, + 0xe2, 0x02, 0x7a, 0x81, 0x7d, 0x49, 0xdd, 0x8c, 0x26, 0x05, + 0xfe, 0xed, 0xa8, 0x12, 0xa4, 0x3d, 0x82, 0x65, 0x3d, 0x87, + 0xed, 0x95, 0x86, 0x80, 0x3f, 0xc6, 0xcd, 0x27, 0x58, 0x56, + 0xca, 0x23, 0xca, 0xa4, 0xd8, 0x06, 0x11, 0xb4, 0x24, 0xc8, + 0x8a, 0xc5, 0x36, 0x42, 0xe3, 0xd4, 0xf7, 0xaf, 0x74, 0xac, + 0x89, 0xee, 0x47, 0x2e, 0x8b, 0xde, 0xd0, 0x85, 0xd4, 0x2e, + 0xb4, 0xae, 0x99, 0x96, 0x88, 0xe2, 0x60, 0x99, 0xfb, 0x62, + 0x5f, 0x8b, 0xa7, 0x24, 0xe2, 0xc3, 0x72, 0x4c, 0x6f, 0x1d, + 0xcd, 0xc1, 0x3a, 0x32, 0x06, 0x98, 0xb5, 0x92, 0x82, 0x98, + 0xb1, 0x7d, 0xca, 0xa1, 0xe1, 0x4d, 0xe1, 0xe5, 0xaf, 0x3a, + 0x08, 0x0d, 0x68, 0x33, 0xb8, 0xc0, 0xc3, 0xfd, 0xb9, 0x90, + 0x47, 0x58, 0xca, 0xb2, 0x8d, 0x2d, 0x75, 0x7d, 0xbb, 0xd3, + 0xc3, 0x0f, 0x7d, 0xa7, 0x5a, 0x5a, 0x25, 0x6f, 0x12, 0xd8, + 0x69, 0xd4, 0xc1, 0x20, 0x19, 0x65, 0x4d, 0x36, 0x7c, 0x7f, + 0xc4, 0x47, 0x00, 0xcb, 0x2c, 0x64, 0x13, 0x06, 0x0a, 0x37, + 0x1d, 0x1d, 0x7d, 0x89, 0x9c, 0x21, 0xd0, 0xaa, 0xa9, 0x01, + 0xee, 0xb2, 0x70, 0xc7, 0xc3, 0x11, 0x60, 0xd9, 0x73, 0xc9, + 0xea, 0x6d, 0x8a, 0x1b, 0x0f, 0x69, 0x1d, 0xb3, 0x95, 0x82, + 0x52, 0xf4, 0xa9, 0x4e, 0x25, 0x85, 0x75, 0xde, 0x12, 0x3c, + 0x11, 0x71, 0x06, 0x88, 0xf0, 0x39, 0x93, 0x29, 0x3a, 0x94, + 0x7c, 0x73, 0x42, 0xea, 0x59, 0x7c, 0x1d, 0x93, 0x1a, 0x14, + 0x10, 0x4c, 0x5e, 0x92, 0x1a, 0x9e, 0x71, 0xf1, 0x42, 0xb9, + 0x72, 0x13, 0x7d, 0x99, 0x4a, 0x28, 0x8b, 0x92, 0x48, 0x1d, + 0x78, 0x19, 0x04, 0xf8, 0xc4, 0xf3, 0xb1, 0x1c, 0x2f, 0x56, + 0xb6, 0xf6, 0x87, 0x00, 0xbd, 0x8c, 0x8c, 0x56, 0xe1, 0x38, + 0xf8, 0x6d, 0x19, 0xe7, 0x7e, 0x30, 0x52, 0xc6, 0x47, 0x72, + 0xc9, 0xa1, 0x30, 0xef, 0x8c, 0xf6, 0x23, 0xbf, 0xfb, 0xd0, + 0xbb, 0x51, 0xa9, 0xf6, 0x1d, 0xa7, 0xd2, 0xc7, 0xaa, 0xa6, + 0xc8, 0xa6, 0xa6, 0x61, 0x8f, 0x8c, 0x22, 0xee, 0x6e, 0xb5, + 0x21, 0x89, 0x72, 0x0e, 0xbe, 0x00, 0xcf, 0x08, 0x80, 0x09, + 0x06, 0x4d, 0xd4, 0xd4, 0xea, 0xb6, 0xa0, 0x8e, 0x71, 0xc8, + 0x73, 0x16, 0xdb, 0x55, 0x0f, 0xed, 0xbf, 0xb7, 0x40, 0x41, + 0x9a, 0x47, 0xfc, 0xad, 0x5b, 0xf4, 0x86, 0x3c, 0x98, 0xd1, + 0xaa, 0x51, 0x15, 0xc3, 0x10, 0x55, 0x8e, 0x5d, 0xf7, 0x9d, + 0xd4, 0x11, 0x35, 0xe7, 0x05, 0x11, 0x7d, 0x0f, 0x2b, 0x44, + 0xfe, 0x12, 0x7f, 0x39, 0xa6, 0x19, 0x91, 0x8b, 0xd0, 0xac, + 0x2c, 0x18, 0x63, 0x6a, 0x33, 0xc2, 0x75, 0xd2, 0xcd, 0xf7, + 0x22, 0x46, 0xca, 0xd1, 0xf9, 0xc0, 0x15, 0x08, 0xc7, 0x10, + 0x67, 0xd1, 0x42, 0x13, 0x27, 0x22, 0xc3, 0xe3, 0x94, 0x66, + 0x00, 0xbf, 0x2f, 0x7d, 0xfb, 0xc5, 0x6f, 0xb9, 0x03, 0x24, + 0xce, 0xfb, 0xf4, 0x6b, 0xad, 0xe0, 0x47, 0xda, 0x5f, 0xea, + 0x61, 0xfd, 0x6a, 0x76, 0x98, 0x15, 0x76, 0x72, 0xef, 0x95, + 0x77, 0x93, 0x3b, 0x23, 0xde, 0x09, 0x38, 0x1c, 0x7b, 0xd5, + 0xd1, 0x5c, 0xc5, 0xc4, 0x34, 0x0c, 0xd8, 0xc2, 0x05, 0xb7, + 0xe5, 0xb5, 0xc9, 0x7b, 0xc1, 0x28, 0xea, 0xc8, 0x07, 0x98, + 0xe2, 0xab, 0x73, 0x24, 0xfb, 0xef, 0xce, 0x0a, 0xa7, 0xb9, + 0x8d, 0xeb, 0x31, 0x09, 0x82, 0xf2, 0x9c, 0x4d, 0xf1, 0x1a, + 0x4a, 0x79, 0x35, 0xa7, 0x7b, 0x7b, 0xf0, 0xa9, 0xe7, 0xb9, + 0xf9, 0x52, 0x63, 0x73, 0x29, 0xe4, 0xd4, 0x13, 0x19, 0x2a, + 0xf2, 0x9d, 0x4e, 0xcc, 0x2a, 0xb3, 0xdf, 0x95, 0xc5, 0xb6, + 0x91, 0x34, 0xf4, 0x10, 0x2e, 0xe7, 0x0d, 0xf8, 0x3a, 0x6d, + 0xdd, 0x30, 0x57, 0xec, 0x05, 0x70, 0xef, 0x80, 0x8c, 0x8a, + 0xe1, 0x2e, 0x9e, 0xd4, 0xd1, 0xb4, 0xdc, 0x14, 0x87, 0xf5, + 0x97, 0x4b, 0x2c, 0xd9, 0x93, 0x71, 0x3a, 0x15, 0x25, 0xa0, + 0x8a, 0xb2, 0x93, 0xb5, 0x62, 0xf7, 0x81, 0x09, 0x9c, 0x8d, + 0xe5, 0x09, 0xb2, 0xda, 0x07, 0xf2, 0x33, 0xf6, 0x5c, 0xd2, + 0x71, 0xb1, 0xaf, 0xea, 0x62, 0x05, 0xf3, 0x5f, 0xd9, 0xb1, + 0x8e, 0xd1, 0x5d, 0xf9, 0x89, 0x85, 0x78, 0xd5, 0x54, 0x56, + 0x6c, 0xd4, 0x20, 0x45, 0xe7, 0x03, 0xcc, 0x25, 0x7e, 0xde, + 0x40, 0x3d, 0xb2, 0x46, 0x90, 0x59, 0xc2, 0xfc, 0xdc, 0x15, + 0xd4, 0x80, 0x5b, 0xd8, 0xec, 0x2e, 0x49, 0xd7, 0xd8, 0x45, + 0x0e, 0x7d, 0xba, 0x09, 0x32, 0x60, 0xdb, 0x64, 0xd6, 0x44, + 0xd7, 0xea, 0xb4, 0xb1, 0xb6, 0xfc, 0x1b, 0xde, 0x4a, 0x48, + 0xa1, 0x6c, 0x5b, 0x5a, 0x1f, 0x35, 0x55, 0x18, 0xd2, 0xae, + 0x88, 0x46, 0x5f, 0x2d, 0x25, 0xb0, 0xd9, 0x4f, 0x40, 0xbb, + 0x23, 0x40, 0x9f, 0x85, 0x19, 0x4e, 0xd4, 0xfc, 0xcd, 0xc4, + 0x59, 0x98, 0x27, 0xe2, 0x7e, 0xab, 0x36, 0x52, 0x51, 0x30, + 0xf4, 0xb4, 0xf3, 0xa1, 0x8d, 0x87, 0x01, 0xe5, 0x2d, 0x42, + 0x4b, 0x87, 0x70, 0x95, 0xde, 0x9d, 0x80, 0x36, 0x4e, 0x8a, + 0x14, 0x40, 0x1c, 0x27, 0x89, 0xe1, 0x42, 0xee, 0x77, 0x87, + 0x4f, 0x4d, 0xb0, 0x38, 0x3f, 0x05, 0x67, 0xe3, 0x9c, 0x88, + 0xd8, 0x68, 0x75, 0xf3, 0xf9, 0x92, 0x8e, 0x78, 0xbe, 0x43, + 0xb9, 0x28, 0xa9, 0x2e, 0xde, 0xc9, 0xbd, 0x48, 0x99, 0x4d, + 0x7d, 0xb6, 0xba, 0x3b, 0x31, 0x20, 0x9f, 0x0c, 0xc4, 0x90, + 0xae, 0x4a, 0x33, 0x17, 0x58, 0x13, 0xb5, 0xfd, 0xec, 0xef, + 0x87, 0x21, 0x0c, 0xce, 0xbd, 0xbd, 0x85, 0x61, 0x07, 0xb8, + 0x7f, 0x93, 0xaa, 0xbd, 0xc6, 0xae, 0x63, 0x2c, 0x12, 0x6a, + 0xaa, 0xe2, 0x9d, 0xf8, 0x55, 0xac, 0xc3, 0xa3, 0x40, 0xf8, + 0xad, 0xfb, 0x21, 0x89, 0x5c, 0x90, 0x21, 0x40, 0x57, 0xfb, + 0x08, 0x5d, 0x28, 0x83, 0xcc, 0x46, 0x76, 0x44, 0x2e, 0xe4, + 0x5b, 0xe7, 0x37, 0x79, 0xc7, 0xc8, 0x0a, 0x0b, 0xc2, 0xb6, + 0x17, 0x48, 0x8c, 0x2b, 0x67, 0xd6, 0xf9, 0x33, 0xe0, 0xbd, + 0x6b, 0xea, 0x79, 0x7d, 0x6d, 0x5b, 0x23, 0x7e, 0x5e, 0x5d, + 0x53, 0xcf, 0x01, 0xea, 0x86, 0x5f, 0x8a, 0x4b, 0x1f, 0x32, + 0xcd, 0xdb, 0x30, 0xe3, 0x27, 0x3f, 0x10, 0x4b, 0xba, 0x3c, + 0xf9, 0x42, 0x78, 0x52, 0x01, 0x87, 0xed, 0xf4, 0x15, 0xa4, + 0x8d, 0xa0, 0x1d, 0xc7, 0x89, 0xf5, 0x4f, 0x99, 0x28, 0x04, + 0xa7, 0x87, 0xf8, 0x9b, 0x77, 0x18, 0x0a, 0xb8, 0x59, 0xf3, + 0xcd, 0x74, 0xf1, 0xd5, 0x13, 0x61, 0xca, 0x02, 0x95, 0xe6, + 0x50, 0x30, 0x96, 0x83, 0x35, 0xf8, 0xd2, 0xea, 0xd7, 0xd6, + 0x5f, 0xbf, 0xab, 0x9b, 0x91, 0xc9, 0xc4, 0x93, 0x57, 0xb5, + 0x55, 0xb6, 0x83, 0xb0, 0x83, 0x17, 0x78, 0xc9, 0xb6, 0xa5, + 0x55, 0x9b, 0x2d, 0x08, 0x1f, 0x09, 0x37, 0x1c, 0x0a, 0x3a, + 0xdc, 0x32, 0xeb, 0x20 + }; + + const uint8_t *key = &static_keys_a[(nonce[0] >> 3) * 0x70]; + for(size_t i=0; i> 3) * 0x70]; + for(size_t i=0; ibright, rpcrypt->ambassador, nonce, morning); + const uint8_t keys_1[] = { + 0xc8, 0x48, 0xc2, 0xb4, 0x08, 0xeb, 0x88, 0xf7, 0x5f, 0x4a, + 0x09, 0x2d, 0x59, 0x1f, 0x09, 0xcd, 0x1c, 0x18, 0xf4, 0x7a, + 0x28, 0x4a, 0x96, 0x6d, 0xb3, 0x59, 0x71, 0x53, 0x75, 0x7e, + 0x82, 0x50, 0x57, 0xe4, 0x59, 0xb3, 0xf4, 0x49, 0x69, 0x40, + 0xeb, 0x17, 0xc9, 0x9f, 0x17, 0x97, 0x71, 0xae, 0xc9, 0x60, + 0x7f, 0xf8, 0x2e, 0x08, 0x94, 0xe8, 0x43, 0xea, 0xda, 0x6b, + 0xe5, 0x19, 0x59, 0x33, 0x1f, 0x89, 0xae, 0x47, 0x57, 0x7b, + 0x1c, 0x66, 0xfe, 0xff, 0x95, 0xbf, 0x55, 0x6b, 0xd5, 0x93, + 0x27, 0xea, 0xa6, 0x24, 0x67, 0x39, 0x9f, 0xd3, 0x0c, 0xaa, + 0x26, 0x42, 0xe7, 0x66, 0x4d, 0xd8, 0x18, 0x75, 0xfe, 0x44, + 0x03, 0x46, 0xee, 0x3e, 0xf8, 0x3c, 0xb7, 0x85, 0x97, 0x03, + 0x07, 0x06, 0x92, 0xff, 0x59, 0x17, 0x27, 0x0b, 0x21, 0xf7, + 0x05, 0x7f, 0x69, 0x90, 0x0e, 0x38, 0x91, 0xc6, 0x67, 0x23, + 0x48, 0xba, 0x08, 0x8e, 0x57, 0xdd, 0x91, 0xd0, 0x40, 0x47, + 0x1c, 0x5b, 0xbf, 0xc8, 0x06, 0x3f, 0x96, 0xa0, 0xdc, 0x00, + 0xe5, 0x9a, 0xf5, 0x3b, 0x90, 0x80, 0x66, 0xbb, 0x0f, 0x93, + 0x30, 0x07, 0x2b, 0x56, 0x45, 0xa0, 0x9a, 0xb1, 0xb0, 0x72, + 0x0c, 0xe4, 0xdd, 0x70, 0xdd, 0x7c, 0x5a, 0xbf, 0xd4, 0xe8, + 0x0d, 0xca, 0x37, 0xe5, 0x0e, 0xfd, 0x12, 0xee, 0x79, 0x9a, + 0x5e, 0xa7, 0x1e, 0x31, 0xaf, 0x1f, 0x46, 0x52, 0xca, 0xf3, + 0x42, 0x00, 0x3d, 0xf2, 0x89, 0x7c, 0x1c, 0x77, 0x60, 0xb7, + 0x4a, 0x80, 0x76, 0x47, 0x4b, 0x3f, 0xb6, 0x91, 0x2f, 0x9c, + 0xc2, 0xf1, 0xad, 0x44, 0x29, 0xcb, 0x32, 0x8c, 0x0a, 0x8d, + 0x05, 0x75, 0x46, 0xa1, 0xf8, 0xda, 0x1a, 0xa7, 0x20, 0xde, + 0x32, 0x59, 0xfe, 0x70, 0xb5, 0x87, 0xf3, 0x92, 0xfd, 0xb4, + 0xdf, 0xf4, 0xa6, 0xe3, 0x7d, 0x98, 0x3b, 0xe1, 0xba, 0x18, + 0xdb, 0x61, 0xd1, 0xc2, 0xa6, 0xee, 0x08, 0x25, 0xfa, 0x86, + 0x8a, 0x7b, 0xfe, 0xbc, 0x02, 0xbd, 0x22, 0x5f, 0x25, 0x30, + 0x51, 0x5d, 0x28, 0x36, 0x5a, 0x29, 0x8e, 0x52, 0xeb, 0x49, + 0x14, 0x28, 0x7f, 0x0a, 0xc4, 0x69, 0x25, 0x85, 0x6b, 0xec, + 0x33, 0x33, 0x57, 0xab, 0x50, 0x13, 0xcf, 0xe7, 0x73, 0x78, + 0x23, 0x06, 0x4d, 0x1f, 0xbb, 0x38, 0x11, 0xb1, 0x6e, 0x6c, + 0x6f, 0xcd, 0x4b, 0x0e, 0x42, 0x85, 0x80, 0xbb, 0xa8, 0x39, + 0x68, 0xc9, 0x5b, 0xbb, 0x46, 0x58, 0x86, 0x88, 0x57, 0x88, + 0x5e, 0xea, 0x7c, 0x37, 0xdf, 0xfd, 0x02, 0x39, 0x45, 0x89, + 0x2e, 0xf2, 0xe4, 0xf0, 0x08, 0xc0, 0xb6, 0xeb, 0x9c, 0x6e, + 0x7a, 0x81, 0xa3, 0x26, 0x46, 0xfe, 0xe1, 0x70, 0x3c, 0x3e, + 0x11, 0x7a, 0x32, 0xce, 0x45, 0x02, 0x7d, 0x32, 0xcd, 0x08, + 0x07, 0x06, 0xa3, 0xa8, 0xf7, 0x34, 0xfe, 0xee, 0x06, 0xb0, + 0x14, 0xd6, 0x6b, 0x2d, 0x2e, 0x01, 0xaf, 0x77, 0x11, 0xec, + 0x1f, 0x31, 0x38, 0x17, 0x9c, 0xd0, 0xe0, 0xc5, 0x4d, 0xa4, + 0xd6, 0xad, 0xb9, 0xe6, 0xe1, 0xe3, 0xe2, 0x9e, 0x44, 0x91, + 0x9a, 0x5e, 0x26, 0xca, 0xcc, 0xda, 0x4d, 0xd7, 0x78, 0x6a, + 0x75, 0xa6, 0x19, 0xad, 0xcc, 0x62, 0xc7, 0xb6, 0x0d, 0x14, + 0xb1, 0xbe, 0xeb, 0xcb, 0x10, 0xcf, 0xa9, 0xee, 0xe2, 0x42, + 0x08, 0x35, 0x8a, 0x5c, 0xbc, 0xf1, 0x49, 0xfe, 0x64, 0x78, + 0x03, 0x49, 0x0c, 0x85, 0xf0, 0xe4, 0x77, 0x26, 0xd2, 0x5e, + 0xf5, 0xc1, 0x3b, 0x3d, 0x2d, 0xcc, 0xcf, 0x2a, 0xac, 0xed, + 0x88, 0x52, 0x74, 0x6d, 0xbf, 0xb2, 0xb9, 0xf7, 0x58, 0x51, + 0x1c, 0x50, 0xf6, 0x3d, 0xf2, 0xc4, 0x47, 0x0a, 0x21, 0x30, + 0x47, 0x81, 0x2d, 0xe4, 0x75, 0x0d, 0x8f, 0x2d, 0x22, 0xb0, + 0x63, 0x27 + }; + + for(size_t i=0; itarget = target; + chiaki_rpcrypt_bright_ambassador(target, rpcrypt->bright, rpcrypt->ambassador, nonce, morning); +} + +CHIAKI_EXPORT void chiaki_rpcrypt_init_regist_ps4_pre10(ChiakiRPCrypt *rpcrypt, const uint8_t *ambassador, uint32_t pin) +{ + rpcrypt->target = CHIAKI_TARGET_PS4_9; // representative, might not be the actual version + static const uint8_t regist_aes_key[CHIAKI_RPCRYPT_KEY_SIZE] = + { 0x3f, 0x1c, 0xc4, 0xb6, 0xdc, 0xbb, 0x3e, 0xcc, 0x50, 0xba, 0xed, 0xef, 0x97, 0x34, 0xc7, 0xc9 }; memcpy(rpcrypt->ambassador, ambassador, sizeof(rpcrypt->ambassador)); memcpy(rpcrypt->bright, regist_aes_key, sizeof(rpcrypt->bright)); rpcrypt->bright[0] ^= (uint8_t)((pin >> 0x18) & 0xff); @@ -83,10 +911,101 @@ CHIAKI_EXPORT void chiaki_rpcrypt_init_regist(ChiakiRPCrypt *rpcrypt, const uint rpcrypt->bright[3] ^= (uint8_t)((pin >> 0x00) & 0xff); } +CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_init_regist(ChiakiRPCrypt *rpcrypt, const uint8_t *ambassador, size_t key_0_off, uint32_t pin) +{ + static const uint8_t keys_0[] = { + 0xbe, 0xce, 0x5d, 0xf0, 0xc1, 0x7d, 0xb5, 0xd0, 0xcb, 0x30, + 0x13, 0x5d, 0xaa, 0x56, 0x23, 0xfb, 0xc4, 0xbc, 0xf1, 0x8f, + 0x38, 0x57, 0xfb, 0xd4, 0xd4, 0x3f, 0x26, 0x38, 0xb5, 0xce, + 0xed, 0x6a, 0x21, 0xbc, 0x38, 0xd0, 0x1e, 0x68, 0xcc, 0x7b, + 0x45, 0xd1, 0xbe, 0x42, 0x1a, 0x08, 0xaa, 0x16, 0xfd, 0xb0, + 0xc0, 0xf4, 0xda, 0x35, 0xe9, 0x12, 0xfd, 0x21, 0x07, 0x48, + 0x34, 0xc1, 0xfc, 0x9f, 0x8c, 0xb6, 0xcb, 0x5d, 0xb2, 0x9c, + 0x84, 0xe0, 0x1a, 0xfa, 0xa0, 0xc7, 0xeb, 0x3a, 0x93, 0xb3, + 0xb3, 0xf1, 0x15, 0xaf, 0x13, 0xbd, 0x21, 0xab, 0xea, 0x5b, + 0x80, 0x50, 0x6b, 0x31, 0x1d, 0x7c, 0x1d, 0x40, 0xba, 0x3c, + 0x56, 0x0e, 0xe7, 0x94, 0x3a, 0x5b, 0xa1, 0x40, 0x80, 0x74, + 0x0a, 0xad, 0x28, 0xcf, 0x47, 0xdf, 0x42, 0xa6, 0x69, 0xe9, + 0x5e, 0xbb, 0xc0, 0xc0, 0x0e, 0xb2, 0xc5, 0x8a, 0xee, 0x08, + 0x03, 0xd2, 0x84, 0xe5, 0x91, 0x00, 0x1d, 0x46, 0x06, 0x55, + 0x09, 0x9d, 0x39, 0x9f, 0xd8, 0xe7, 0xfd, 0xad, 0x9e, 0x93, + 0x97, 0xc5, 0xea, 0xe7, 0xa3, 0x10, 0xa7, 0xf2, 0xa2, 0x93, + 0x7f, 0x07, 0x04, 0xb4, 0xee, 0xbb, 0xbf, 0x88, 0x23, 0x9c, + 0x6e, 0xa7, 0x62, 0xb1, 0x4b, 0x67, 0x1e, 0xb8, 0x3b, 0x1f, + 0x64, 0x93, 0x5a, 0x99, 0xec, 0xda, 0xfd, 0x0c, 0x6a, 0xb7, + 0xfe, 0xe4, 0x12, 0x76, 0x32, 0x65, 0xb8, 0x41, 0x23, 0xd1, + 0x17, 0x09, 0x9c, 0x24, 0x2d, 0x5c, 0x9d, 0x12, 0x79, 0xde, + 0xa1, 0xce, 0x69, 0xac, 0xa4, 0xbc, 0x39, 0x2f, 0x57, 0x38, + 0x84, 0x61, 0x2d, 0x2a, 0xe8, 0x04, 0xf8, 0xd5, 0x9d, 0x0b, + 0xff, 0x7e, 0x56, 0x0c, 0xec, 0x87, 0x0a, 0x1e, 0xab, 0xdf, + 0x93, 0x81, 0x13, 0xee, 0xcf, 0x32, 0x02, 0x5a, 0xbf, 0xb0, + 0x17, 0xb7, 0xba, 0xb5, 0x7f, 0xf0, 0x01, 0x7b, 0xe1, 0xcb, + 0x39, 0x7e, 0x60, 0x6d, 0xa4, 0x75, 0x6e, 0x29, 0x92, 0x45, + 0xa6, 0x4f, 0x74, 0x00, 0x86, 0x78, 0x73, 0xbe, 0xfd, 0x3e, + 0xe0, 0xd1, 0x0c, 0x6c, 0x0b, 0x49, 0x09, 0x83, 0x6c, 0x85, + 0x8a, 0x1d, 0xcb, 0x16, 0xce, 0x81, 0x7c, 0x49, 0xc9, 0x2c, + 0x63, 0x61, 0xde, 0xe2, 0x3f, 0x98, 0xb2, 0x73, 0xf0, 0x9a, + 0xec, 0x7b, 0x7c, 0xf1, 0xc9, 0xe1, 0x7f, 0xa5, 0x19, 0x8b, + 0x4b, 0xe8, 0x38, 0xa4, 0x34, 0x7d, 0xf4, 0x28, 0xfe, 0x0d, + 0x4d, 0x11, 0x57, 0x0c, 0x95, 0xf1, 0xaf, 0xd7, 0x34, 0x80, + 0xf4, 0xeb, 0x9b, 0x50, 0xe6, 0x6a, 0x5d, 0xea, 0xce, 0x0c, + 0x85, 0x4e, 0xc5, 0x5b, 0x93, 0x44, 0xc4, 0x24, 0x98, 0x80, + 0xfc, 0xf7, 0x72, 0x9c, 0x31, 0x0b, 0xee, 0x89, 0x67, 0xb3, + 0xa2, 0x69, 0x4f, 0xb3, 0x79, 0x5a, 0x14, 0x02, 0x70, 0xed, + 0x50, 0x13, 0x75, 0x00, 0x6a, 0xf3, 0xc6, 0x05, 0x1a, 0x00, + 0x33, 0x34, 0xf5, 0xac, 0x9e, 0x04, 0xdb, 0xc2, 0x00, 0xb0, + 0x1b, 0xc4, 0xf3, 0x97, 0x9d, 0x7f, 0xbe, 0xb8, 0x23, 0x8d, + 0x99, 0xe7, 0xcb, 0x74, 0x37, 0x4c, 0x57, 0xec, 0xd2, 0x69, + 0x49, 0x46, 0x75, 0x74, 0xaf, 0x51, 0x40, 0xa4, 0x11, 0x7b, + 0xb3, 0x2f, 0x51, 0xda, 0xe2, 0xef, 0x33, 0x73, 0x12, 0x18, + 0x25, 0x39, 0x03, 0x09, 0xca, 0x49, 0xdc, 0x8e, 0xf1, 0x94, + 0xd7, 0x80, 0x17, 0x9e, 0x87, 0x46, 0xc1, 0x04, 0x78, 0xd1, + 0xe5, 0x3d, 0x25, 0x88, 0xec, 0x72, 0x3a, 0x28, 0x41, 0x68, + 0x14, 0x6e, 0x10, 0xe4, 0xc9, 0x57, 0x75, 0x90, 0xfe, 0x22, + 0x1a, 0x63, 0x8e, 0xf4, 0xb8, 0x8d, 0x1a, 0x36, 0xfd, 0xb6, + 0xcb, 0x72, 0xc2, 0x97, 0x52, 0x9f, 0x91, 0x72, 0x1b, 0x75, + 0x57, 0x90, 0x3b, 0xfd, 0x5a, 0x93, 0x8c, 0xdb, 0xfc, 0xa3, + 0x03, 0xdf + }; + + if(key_0_off >= 0x20) + return CHIAKI_ERR_INVALID_DATA; + + rpcrypt->target = CHIAKI_TARGET_PS4_10; // representative, might not be the actual version + + memcpy(rpcrypt->ambassador, ambassador, sizeof(rpcrypt->ambassador)); + + for(size_t i=0; ibright[i] = keys_0[i*0x20 + key_0_off]; + rpcrypt->bright[0xc] ^= (uint8_t)((pin >> 0x18) & 0xff); + rpcrypt->bright[0xd] ^= (uint8_t)((pin >> 0x10) & 0xff); + rpcrypt->bright[0xe] ^= (uint8_t)((pin >> 0x08) & 0xff); + rpcrypt->bright[0xf] ^= (uint8_t)((pin >> 0x00) & 0xff); + + return CHIAKI_ERR_SUCCESS; +} + +#define HMAC_KEY_SIZE 0x10 +static const uint8_t hmac_key[HMAC_KEY_SIZE] = { 0x20, 0xd6, 0x6f, 0x59, 0x04, 0xea, 0x7c, 0x14, 0xe5, 0x57, 0xff, 0xc5, 0x2e, 0x48, 0x8a, 0xc8 }; +static const uint8_t hmac_key_ps4_pre10[HMAC_KEY_SIZE] = { 0xac, 0x07, 0x88, 0x83, 0xc8, 0x3a, 0x1f, 0xe8, 0x11, 0x46, 0x3a, 0xf3, 0x9e, 0xe3, 0xe3, 0x77 }; + +static const uint8_t *rpcrypt_hmac_key(ChiakiRPCrypt *rpcrypt) +{ + switch(rpcrypt->target) + { + case CHIAKI_TARGET_PS4_8: + case CHIAKI_TARGET_PS4_9: + return hmac_key_ps4_pre10; + default: + return hmac_key; + } +} + + #ifdef CHIAKI_LIB_ENABLE_MBEDTLS 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 }; + const uint8_t *hmac_key = rpcrypt_hmac_key(rpcrypt); uint8_t buf[CHIAKI_RPCRYPT_KEY_SIZE + 8]; memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE); @@ -114,7 +1033,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, } while(0) // https://tls.mbed.org/module-level-design-hashing GOTO_ERROR(mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(type) , 1)); - GOTO_ERROR(mbedtls_md_hmac_starts(&ctx, hmac_key, sizeof(hmac_key))); + GOTO_ERROR(mbedtls_md_hmac_starts(&ctx, hmac_key, HMAC_KEY_SIZE)); GOTO_ERROR(mbedtls_md_hmac_update(&ctx, (const unsigned char *) buf, sizeof(buf))); GOTO_ERROR(mbedtls_md_hmac_finish(&ctx, hmac)); #undef GOTO_ERROR @@ -172,7 +1091,7 @@ error: #else 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 }; + const uint8_t *hmac_key = rpcrypt_hmac_key(rpcrypt); uint8_t buf[CHIAKI_RPCRYPT_KEY_SIZE + 8]; memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE); diff --git a/lib/src/session.c b/lib/src/session.c index db86c70..caf8236 100644 --- a/lib/src/session.c +++ b/lib/src/session.c @@ -46,7 +46,7 @@ #define SESSION_EXPECT_TIMEOUT_MS 5000 static void *session_thread_func(void *arg); -static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersion *server_version_out); +static bool session_thread_request_session(ChiakiSession *session, ChiakiTarget *target_out); const char *chiaki_rp_application_reason_string(uint32_t reason) { @@ -67,26 +67,30 @@ const char *chiaki_rp_application_reason_string(uint32_t reason) } } -const char *chiaki_rp_version_string(ChiakiRpVersion version) +const char *chiaki_rp_version_string(ChiakiTarget version) { switch(version) { - case CHIAKI_RP_VERSION_8_0: + case CHIAKI_TARGET_PS4_8: return "8.0"; - case CHIAKI_RP_VERSION_9_0: + case CHIAKI_TARGET_PS4_9: return "9.0"; + case CHIAKI_TARGET_PS4_10: + return "10.0"; default: return NULL; } } -CHIAKI_EXPORT ChiakiRpVersion chiaki_rp_version_parse(const char *rp_version_str) +CHIAKI_EXPORT ChiakiTarget chiaki_rp_version_parse(const char *rp_version_str) { if(strcmp(rp_version_str, "8.0") == 0) - return CHIAKI_RP_VERSION_8_0; + return CHIAKI_TARGET_PS4_8; if(strcmp(rp_version_str, "9.0") == 0) - return CHIAKI_RP_VERSION_9_0; - return CHIAKI_RP_VERSION_UNKNOWN; + return CHIAKI_TARGET_PS4_9; + if(strcmp(rp_version_str, "10.0") == 0) + return CHIAKI_TARGET_PS4_10; + return CHIAKI_TARGET_PS4_UNKNOWN; } CHIAKI_EXPORT void chiaki_connect_video_profile_preset(ChiakiConnectVideoProfile *profile, ChiakiVideoResolutionPreset resolution, ChiakiVideoFPSPreset fps) @@ -174,7 +178,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_session_init(ChiakiSession *session, Chiaki session->log = log; session->quit_reason = CHIAKI_QUIT_REASON_NONE; - session->rp_version = CHIAKI_RP_VERSION_9_0; + session->target = CHIAKI_TARGET_PS4_10; ChiakiErrorCode err = chiaki_cond_init(&session->state_cond); if(err != CHIAKI_ERR_SUCCESS) @@ -369,13 +373,20 @@ static void *session_thread_func(void *arg) CHIAKI_LOGI(session->log, "Starting session request"); - ChiakiRpVersion server_rp_version = CHIAKI_RP_VERSION_UNKNOWN; - success = session_thread_request_session(session, &server_rp_version); + ChiakiTarget server_target = CHIAKI_TARGET_PS4_UNKNOWN; + success = session_thread_request_session(session, &server_target); - if(!success && server_rp_version != CHIAKI_RP_VERSION_UNKNOWN) + if(!success && server_target != CHIAKI_TARGET_PS4_UNKNOWN) { CHIAKI_LOGI(session->log, "Attempting to re-request session with Server's RP-Version"); - session->rp_version = server_rp_version; + session->target = server_target; + success = session_thread_request_session(session, &server_target); + } + + if(!success && server_target != CHIAKI_TARGET_PS4_UNKNOWN) + { + CHIAKI_LOGI(session->log, "Attempting to re-request session even harder with Server's RP-Version!!!"); + session->target = server_target; success = session_thread_request_session(session, NULL); } @@ -384,7 +395,7 @@ static void *session_thread_func(void *arg) CHIAKI_LOGI(session->log, "Session request successful"); - chiaki_rpcrypt_init_auth(&session->rpcrypt, session->nonce, session->connect_info.morning); + chiaki_rpcrypt_init_auth(&session->rpcrypt, session->target, 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); @@ -584,9 +595,9 @@ static void parse_session_response(SessionResponse *response, ChiakiHttpResponse /** - * @param server_version_out if NULL, version mismatch means to fail the entire session, otherwise report the version here + * @param target_out if NULL, version mismatch means to fail the entire session, otherwise report the target here */ -static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersion *server_version_out) +static bool session_thread_request_session(ChiakiSession *session, ChiakiTarget *target_out) { chiaki_socket_t session_sock = CHIAKI_INVALID_SOCKET; for(struct addrinfo *ai=session->connect_info.host_addrinfos; ai; ai=ai->ai_next) @@ -676,7 +687,7 @@ static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersi CHIAKI_LOGI(session->log, "Connected to %s:%d", session->connect_info.hostname, SESSION_PORT); static const char session_request_fmt[] = - "GET /sce/rp/session HTTP/1.1\r\n" + "GET %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: remoteplay Windows\r\n" "Connection: close\r\n" @@ -684,6 +695,9 @@ static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersi "RP-Registkey: %s\r\n" "Rp-Version: %s\r\n" "\r\n"; + const char *path = (session->target == CHIAKI_TARGET_PS4_8 || session->target == CHIAKI_TARGET_PS4_9) + ? "/sce/rp/session" + : "/sie/ps4/rp/sess/init"; size_t regist_key_len = sizeof(session->connect_info.regist_key); for(size_t i=0; irp_version); + const char *rp_version_str = chiaki_rp_version_string(session->target); char buf[512]; int request_len = snprintf(buf, sizeof(buf), session_request_fmt, - session->connect_info.hostname, SESSION_PORT, regist_key_hex, rp_version_str ? rp_version_str : ""); + path, session->connect_info.hostname, SESSION_PORT, regist_key_hex, rp_version_str ? rp_version_str : ""); if(request_len < 0 || request_len >= sizeof(buf)) { CHIAKI_SOCKET_CLOSE(session_sock); @@ -774,12 +788,20 @@ static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersi session->quit_reason = CHIAKI_QUIT_REASON_SESSION_REQUEST_UNKNOWN; } } - else if(response.error_code == CHIAKI_RP_APPLICATION_REASON_RP_VERSION && server_version_out && response.rp_version) + else if((response.error_code == CHIAKI_RP_APPLICATION_REASON_RP_VERSION + || response.error_code == CHIAKI_RP_APPLICATION_REASON_UNKNOWN) + && target_out && response.rp_version && strcmp(rp_version_str, response.rp_version)) { - CHIAKI_LOGI(session->log, "Reported RP-Version mismatch. ours = %s, server = %s", rp_version_str ? rp_version_str : "", response.rp_version); - *server_version_out = chiaki_rp_version_parse(response.rp_version); - if(*server_version_out != CHIAKI_RP_VERSION_UNKNOWN) - CHIAKI_LOGI(session->log, "Detected Server RP-Version %s", chiaki_rp_version_string(*server_version_out)); + CHIAKI_LOGI(session->log, "Reported RP-Version mismatch. ours = %s, server = %s", + rp_version_str ? rp_version_str : "", response.rp_version); + *target_out = chiaki_rp_version_parse(response.rp_version); + if(*target_out != CHIAKI_TARGET_PS4_UNKNOWN) + CHIAKI_LOGI(session->log, "Detected Server RP-Version %s", chiaki_rp_version_string(*target_out)); + else if(!strcmp(response.rp_version, "5.0")) + { + CHIAKI_LOGI(session->log, "Reported Server RP-Version is 5.0. This is probably nonsense, let's try with 9.0"); + *target_out = CHIAKI_TARGET_PS4_9; + } else { CHIAKI_LOGE(session->log, "Server RP-Version is unknown"); diff --git a/test/regist.c b/test/regist.c index 866eeb8..d2a4aee 100644 --- a/test/regist.c +++ b/test/regist.c @@ -24,25 +24,25 @@ static const uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE] = { 0x13, 0x37, 0xde, 0 static const uint32_t pin = 13374201; static const char * const psn_id = "ChiakiNanami1337"; -static MunitResult test_aeropause(const MunitParameter params[], void *user) +static MunitResult test_aeropause_ps4_pre10(const MunitParameter params[], void *user) { uint8_t expected[CHIAKI_RPCRYPT_KEY_SIZE] = { 0x0b, 0xe1, 0x2f, 0xbb, 0x4c, 0x7c, 0x99, 0x4a, 0x41, 0x1e, 0x2d, 0x4c, 0xa4, 0x19, 0xf4, 0x35 }; uint8_t aeropause[CHIAKI_RPCRYPT_KEY_SIZE]; - chiaki_rpcrypt_aeropause(aeropause, ambassador); + chiaki_rpcrypt_aeropause_ps4_pre10(aeropause, ambassador); munit_assert_memory_equal(sizeof(expected), aeropause, expected); return MUNIT_OK; } -static MunitResult test_pin_bright(const MunitParameter params[], void *user) +static MunitResult test_pin_bright_ps4_pre10(const MunitParameter params[], void *user) { uint8_t expected[CHIAKI_RPCRYPT_KEY_SIZE] = { 0x3f, 0xd0, 0xd6, 0x4f, 0xdc, 0xbb, 0x3e, 0xcc, 0x50, 0xba, 0xed, 0xef, 0x97, 0x34, 0xc7, 0xc9 }; ChiakiRPCrypt rpcrypt; - chiaki_rpcrypt_init_regist(&rpcrypt, ambassador, pin); + chiaki_rpcrypt_init_regist_ps4_pre10(&rpcrypt, ambassador, pin); munit_assert_memory_equal(sizeof(expected), rpcrypt.bright, expected); return MUNIT_OK; } -static MunitResult test_request_payload(const MunitParameter params[], void *user) +static MunitResult test_request_payload_ps4_pre10(const MunitParameter params[], void *user) { uint8_t expected[] = { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, @@ -65,11 +65,10 @@ static MunitResult test_request_payload(const MunitParameter params[], void *use }; ChiakiRPCrypt rpcrypt; - chiaki_rpcrypt_init_regist(&rpcrypt, ambassador, pin); uint8_t payload[0x400]; size_t payload_size = sizeof(payload); - ChiakiErrorCode err = chiaki_regist_request_payload_format(payload, &payload_size, &rpcrypt, psn_id, NULL); + ChiakiErrorCode err = chiaki_regist_request_payload_format(CHIAKI_TARGET_PS4_9, ambassador, payload, &payload_size, &rpcrypt, psn_id, NULL, pin); munit_assert_int(err, ==, CHIAKI_ERR_SUCCESS); munit_assert_size(payload_size, ==, sizeof(expected)); munit_assert_memory_equal(sizeof(expected), payload, expected); @@ -78,28 +77,28 @@ static MunitResult test_request_payload(const MunitParameter params[], void *use MunitTest tests_regist[] = { { - "/aeropause", - test_aeropause, + "/aeropause_ps4_pre10", + test_aeropause_ps4_pre10, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { - "/pin_bright", - test_pin_bright, + "/pin_bright_ps4_pre10", + test_pin_bright_ps4_pre10, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { - "/request_payload", - test_request_payload, + "/request_payload_ps4_pre10", + test_request_payload_ps4_pre10, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } -}; \ No newline at end of file +}; diff --git a/test/rpcrypt.c b/test/rpcrypt.c index e6e7f12..8297d37 100644 --- a/test/rpcrypt.c +++ b/test/rpcrypt.c @@ -19,19 +19,16 @@ #include - -static const uint8_t nonce[] = { 0x43, 0x9, 0x67, 0xae, 0x36, 0x4b, 0x1c, 0x45, 0x26, 0x62, 0x37, 0x7a, 0xbf, 0x3f, 0xe9, 0x39 }; -static const uint8_t morning[] = { 0xd2, 0x78, 0x9f, 0x51, 0x85, 0xa7, 0x99, 0xa2, 0x44, 0x52, 0x77, 0x9c, 0x2b, 0x83, 0xcf, 0x7 }; - - -static MunitResult test_bright_ambassador(const MunitParameter params[], void *user) +static MunitResult test_bright_ambassador_ps4_pre10(const MunitParameter params[], void *user) { + static const uint8_t nonce[] = { 0x43, 0x9, 0x67, 0xae, 0x36, 0x4b, 0x1c, 0x45, 0x26, 0x62, 0x37, 0x7a, 0xbf, 0x3f, 0xe9, 0x39 }; + static const uint8_t morning[] = { 0xd2, 0x78, 0x9f, 0x51, 0x85, 0xa7, 0x99, 0xa2, 0x44, 0x52, 0x77, 0x9c, 0x2b, 0x83, 0xcf, 0x7 }; static const uint8_t bright_expected[] = { 0xa4, 0x4e, 0x2a, 0x16, 0x5e, 0x20, 0xd3, 0xf, 0xaa, 0x11, 0x8b, 0xc7, 0x7c, 0xa7, 0xdc, 0x11 }; static const uint8_t ambassador_expected[] = { 0x1d, 0xa8, 0xb9, 0x1f, 0x6e, 0x26, 0x64, 0x2e, 0xbc, 0x8, 0x8b, 0x0, 0x4f, 0x1, 0x5b, 0x52 }; uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; - chiaki_rpcrypt_bright_ambassador(bright, ambassador, nonce, morning); + chiaki_rpcrypt_bright_ambassador(CHIAKI_TARGET_PS4_9, bright, ambassador, nonce, morning); munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, bright, bright_expected); munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, ambassador, ambassador_expected); @@ -39,15 +36,34 @@ static MunitResult test_bright_ambassador(const MunitParameter params[], void *u return MUNIT_OK; } -static MunitResult test_iv(const MunitParameter params[], void *user) +static MunitResult test_bright_ambassador(const MunitParameter params[], void *user) { + static const uint8_t nonce_local[] = { 0xAE, 0x92, 0xE7, 0x64, 0x88, 0x26, 0x51, 0xEF, 0x89, 0x01, 0x8C, 0xFA, 0x69, 0x6C, 0x69, 0x38 }; + static const uint8_t morning_local[] = { 0x74, 0xA5, 0x9C, 0x96, 0x93, 0xC2, 0x08, 0x3B, 0xA6, 0xA8, 0x4B, 0xA0, 0x50, 0xFA, 0x8E, 0x5A }; + static const uint8_t ambassador_expected[] = { 0x92, 0xBE, 0xE2, 0x19, 0xB9, 0xD5, 0xB1, 0xAB, 0xC6, 0x49, 0x45, 0x77, 0xA4, 0x21, 0xE9, 0xBD }; + static const uint8_t bright_expected[] = { 0x67, 0x40, 0x8C, 0x5E, 0x65, 0x66, 0x5A, 0xD2, 0x91, 0xA8, 0x32, 0xEB, 0xE2, 0xD9, 0x0A, 0xBB }; + + uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE]; + uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; + chiaki_rpcrypt_bright_ambassador(CHIAKI_TARGET_PS4_10, bright, ambassador, nonce_local, morning_local); + + munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, ambassador, ambassador_expected); + munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, bright, bright_expected); + + return MUNIT_OK; +} + +static MunitResult test_iv_ps4_pre10(const MunitParameter params[], void *user) +{ + static const uint8_t nonce[] = { 0x43, 0x9, 0x67, 0xae, 0x36, 0x4b, 0x1c, 0x45, 0x26, 0x62, 0x37, 0x7a, 0xbf, 0x3f, 0xe9, 0x39 }; + static const uint8_t morning[] = { 0xd2, 0x78, 0x9f, 0x51, 0x85, 0xa7, 0x99, 0xa2, 0x44, 0x52, 0x77, 0x9c, 0x2b, 0x83, 0xcf, 0x7 }; static const uint8_t iv_a_expected[] = { 0x6, 0x29, 0xbe, 0x4, 0xe9, 0x91, 0x1c, 0x48, 0xb4, 0x5c, 0x2, 0x6d, 0xb7, 0xb7, 0x88, 0x46 }; static const uint8_t iv_b_expected[] = { 0x3f, 0xd0, 0x83, 0xa, 0xc7, 0x30, 0xfc, 0x56, 0x75, 0x2d, 0xbe, 0xb8, 0x2c, 0x68, 0xa7, 0x4 }; ChiakiRPCrypt rpcrypt; ChiakiErrorCode err; - chiaki_rpcrypt_init_auth(&rpcrypt, nonce, morning); + chiaki_rpcrypt_init_auth(&rpcrypt, CHIAKI_TARGET_PS4_9, nonce, morning); uint8_t iv[CHIAKI_RPCRYPT_KEY_SIZE]; @@ -74,14 +90,49 @@ static MunitResult test_iv(const MunitParameter params[], void *user) return MUNIT_OK; } -#include - -static MunitResult test_encrypt(const MunitParameter params[], void *user) +static MunitResult test_iv_regist(const MunitParameter params[], void *user) { + static const uint8_t ambassador[] = { 0x3e, 0x7e, 0x7a, 0x82, 0x59, 0x73, 0xad, 0xab, 0x2f, 0x69, 0x43, 0x46, 0xbd, 0x44, 0xda, 0xb5 }; + static const uint8_t iv_expected[] = { 0xac, 0x48, 0x99, 0x77, 0xf9, 0x2a, 0xc5, 0x5b, 0xb9, 0x09, 0x3c, 0x33, 0xb6, 0x11, 0x3c, 0x46 }; + ChiakiRPCrypt rpcrypt; ChiakiErrorCode err; - chiaki_rpcrypt_init_auth(&rpcrypt, nonce, morning); + chiaki_rpcrypt_init_regist(&rpcrypt, ambassador, 0, 0); + + uint8_t iv[CHIAKI_RPCRYPT_KEY_SIZE]; + + err = chiaki_rpcrypt_generate_iv(&rpcrypt, iv, 0); + if(err != CHIAKI_ERR_SUCCESS) + return MUNIT_ERROR; + munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, iv, iv_expected); + + return MUNIT_OK; +} + +static MunitResult test_bright_regist(const MunitParameter params[], void *user) +{ + static const uint8_t ambassador[] = { 0xdc, 0xa1, 0xc8, 0x4d, 0xfe, 0x50, 0xd6, 0x57, 0x22, 0xda, 0x09, 0x65, 0x42, 0x31, 0xe7, 0xc2 }; + static const uint8_t bright_expected[] = { 0xed, 0xfc, 0x1d, 0xc5, 0xa2, 0xfe, 0x2d, 0x7f, 0x09, 0x19, 0x85, 0x75, 0x33, 0x6c, 0x13, 0x16 }; + size_t key_0_off = 0x1e; + + ChiakiRPCrypt rpcrypt; + ChiakiErrorCode err; + + chiaki_rpcrypt_init_regist(&rpcrypt, ambassador, key_0_off, 78703893); + munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, rpcrypt.bright, bright_expected); + + return MUNIT_OK; +} + +static MunitResult test_encrypt_ps4_pre10(const MunitParameter params[], void *user) +{ + static const uint8_t nonce[] = { 0x43, 0x9, 0x67, 0xae, 0x36, 0x4b, 0x1c, 0x45, 0x26, 0x62, 0x37, 0x7a, 0xbf, 0x3f, 0xe9, 0x39 }; + static const uint8_t morning[] = { 0xd2, 0x78, 0x9f, 0x51, 0x85, 0xa7, 0x99, 0xa2, 0x44, 0x52, 0x77, 0x9c, 0x2b, 0x83, 0xcf, 0x7 }; + ChiakiRPCrypt rpcrypt; + ChiakiErrorCode err; + + chiaki_rpcrypt_init_auth(&rpcrypt, CHIAKI_TARGET_PS4_9, nonce, morning); // less than block size uint8_t buf_a[] = { 0x13, 0x37, 0xc0, 0xff, 0xee }; @@ -118,12 +169,14 @@ static MunitResult test_encrypt(const MunitParameter params[], void *user) return MUNIT_OK; } -static MunitResult test_decrypt(const MunitParameter params[], void *user) +static MunitResult test_decrypt_ps4_pre10(const MunitParameter params[], void *user) { + static const uint8_t nonce[] = { 0x43, 0x9, 0x67, 0xae, 0x36, 0x4b, 0x1c, 0x45, 0x26, 0x62, 0x37, 0x7a, 0xbf, 0x3f, 0xe9, 0x39 }; + static const uint8_t morning[] = { 0xd2, 0x78, 0x9f, 0x51, 0x85, 0xa7, 0x99, 0xa2, 0x44, 0x52, 0x77, 0x9c, 0x2b, 0x83, 0xcf, 0x7 }; ChiakiRPCrypt rpcrypt; ChiakiErrorCode err; - chiaki_rpcrypt_init_auth(&rpcrypt, nonce, morning); + chiaki_rpcrypt_init_auth(&rpcrypt, CHIAKI_TARGET_PS4_9, nonce, morning); // less than block size uint8_t buf_a[] = { 0x8d, 0xd2, 0x1d, 0xfb }; @@ -162,6 +215,14 @@ static MunitResult test_decrypt(const MunitParameter params[], void *user) MunitTest tests_rpcrypt[] = { + { + "/bright_ambassador_ps4_pre10", + test_bright_ambassador_ps4_pre10, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL + }, { "/bright_ambassador", test_bright_ambassador, @@ -171,28 +232,44 @@ MunitTest tests_rpcrypt[] = { NULL }, { - "/iv", - test_iv, + "/iv_ps4_pre10", + test_iv_ps4_pre10, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { - "/encrypt", - test_encrypt, + "/iv_regist", + test_iv_regist, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { - "/decrypt", - test_decrypt, + "/bright_regist", + test_bright_regist, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL + }, + { + "/encrypt_ps4_pre10", + test_encrypt_ps4_pre10, + NULL, + NULL, + MUNIT_TEST_OPTION_NONE, + NULL + }, + { + "/decrypt_ps4_pre10", + test_decrypt_ps4_pre10, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } -}; \ No newline at end of file +};