PS4 Firmware 8.0 Compatibility (Fix #328)

This commit is contained in:
Florian Märkl 2020-10-16 11:01:00 +02:00
commit 4dac2253df
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
20 changed files with 1273 additions and 136 deletions

1
.gitignore vendored
View file

@ -24,3 +24,4 @@ secret.tar
keystore-env.sh keystore-env.sh
compile_commands.json compile_commands.json
.ccls-cache .ccls-cache
.gdb_history

View file

@ -31,6 +31,7 @@ android {
arguments "-DCHIAKI_ENABLE_TESTS=OFF", arguments "-DCHIAKI_ENABLE_TESTS=OFF",
"-DCHIAKI_ENABLE_CLI=OFF", "-DCHIAKI_ENABLE_CLI=OFF",
"-DCHIAKI_ENABLE_GUI=OFF", "-DCHIAKI_ENABLE_GUI=OFF",
"-DCHIAKI_ENABLE_SETSU=OFF",
"-DCHIAKI_ENABLE_ANDROID=ON", "-DCHIAKI_ENABLE_ANDROID=ON",
"-DCHIAKI_LIB_ENABLE_OPUS=OFF", "-DCHIAKI_LIB_ENABLE_OPUS=OFF",
"-DCHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT=ON" "-DCHIAKI_LIB_OPENSSL_EXTERNAL_PROJECT=ON"

View file

@ -702,6 +702,11 @@ JNIEXPORT void JNICALL JNI_FCN(registStart)(JNIEnv *env, jobject obj, jobject re
")V"); ")V");
jclass regist_info_class = E->GetObjectClass(env, regist_info_obj); 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;")); 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")); 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;")); 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")); jint pin = E->GetIntField(env, regist_info_obj, E->GetFieldID(env, regist_info_class, "pin", "I"));
ChiakiRegistInfo regist_info = { 0 }; ChiakiRegistInfo regist_info = { 0 };
regist_info.target = (ChiakiTarget)target_value;
regist_info.host = E->GetStringUTFChars(env, host_string, NULL); regist_info.host = E->GetStringUTFChars(env, host_string, NULL);
regist_info.broadcast = broadcast; regist_info.broadcast = broadcast;
if(psn_online_id_string) if(psn_online_id_string)

View file

@ -3,11 +3,19 @@ package com.metallic.chiaki.lib
import android.os.Parcelable import android.os.Parcelable
import android.util.Log import android.util.Log
import android.view.Surface import android.view.Surface
import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import java.lang.Exception import java.lang.Exception
import java.net.InetSocketAddress import java.net.InetSocketAddress
import kotlin.math.abs 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) enum class VideoResolutionPreset(val value: Int)
{ {
RES_360P(1), RES_360P(1),
@ -316,6 +324,7 @@ class DiscoveryService(
@Parcelize @Parcelize
data class RegistInfo( data class RegistInfo(
val target: Target,
val host: String, val host: String,
val broadcast: Boolean, val broadcast: Boolean,
val psnOnlineId: String?, val psnOnlineId: String?,

View file

@ -28,6 +28,7 @@ import androidx.lifecycle.ViewModelProvider
import com.metallic.chiaki.R import com.metallic.chiaki.R
import com.metallic.chiaki.common.ext.RevealActivity import com.metallic.chiaki.common.ext.RevealActivity
import com.metallic.chiaki.lib.RegistInfo import com.metallic.chiaki.lib.RegistInfo
import com.metallic.chiaki.lib.Target
import kotlinx.android.synthetic.main.activity_regist.* import kotlinx.android.synthetic.main.activity_regist.*
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
@ -63,7 +64,8 @@ class RegistActivity: AppCompatActivity(), RevealActivity
registButton.setOnClickListener { doRegist() } 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.GE_7 -> R.id.ps4VersionGE7RadioButton
RegistViewModel.PS4Version.LT_7 -> R.id.ps4VersionLT7RadioButton RegistViewModel.PS4Version.LT_7 -> R.id.ps4VersionLT7RadioButton
}) })
@ -71,6 +73,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity
ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId -> ps4VersionRadioGroup.setOnCheckedChangeListener { _, checkedId ->
viewModel.ps4Version.value = when(checkedId) viewModel.ps4Version.value = when(checkedId)
{ {
R.id.ps4VersionGE8RadioButton -> RegistViewModel.PS4Version.GE_8
R.id.ps4VersionGE7RadioButton -> RegistViewModel.PS4Version.GE_7 R.id.ps4VersionGE7RadioButton -> RegistViewModel.PS4Version.GE_7
R.id.ps4VersionLT7RadioButton -> RegistViewModel.PS4Version.LT_7 R.id.ps4VersionLT7RadioButton -> RegistViewModel.PS4Version.LT_7
else -> RegistViewModel.PS4Version.GE_7 else -> RegistViewModel.PS4Version.GE_7
@ -78,11 +81,11 @@ class RegistActivity: AppCompatActivity(), RevealActivity
} }
viewModel.ps4Version.observe(this, Observer { 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!!) 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 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 psnId = psnIdEditText.text.toString().trim()
val psnOnlineId: String? = if(ps4Version == RegistViewModel.PS4Version.LT_7) psnId else null val psnOnlineId: String? = if(ps4Version == RegistViewModel.PS4Version.LT_7) psnId else null
val psnAccountId: ByteArray? = 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 } try { Base64.decode(psnId, Base64.DEFAULT) } catch(e: IllegalArgumentException) { null }
else else
null null
val psnIdValid = when(ps4Version) val psnIdValid = when(ps4Version)
{ {
RegistViewModel.PS4Version.GE_7 -> psnAccountId != null && psnAccountId.size == RegistInfo.ACCOUNT_ID_SIZE
RegistViewModel.PS4Version.LT_7 -> psnOnlineId?.isNotEmpty() ?: false 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) if(!psnIdValid)
getString(when(ps4Version) 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 RegistViewModel.PS4Version.LT_7 -> R.string.regist_psn_online_id_invalid
else -> R.string.regist_psn_account_id_invalid
}) })
else else
null null
@ -127,7 +130,14 @@ class RegistActivity: AppCompatActivity(), RevealActivity
if(!hostValid || !psnIdValid || !pinValid) if(!hostValid || !psnIdValid || !pinValid)
return 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 { Intent(this, RegistExecuteActivity::class.java).also {
it.putExtra(RegistExecuteActivity.EXTRA_REGIST_INFO, registInfo) it.putExtra(RegistExecuteActivity.EXTRA_REGIST_INFO, registInfo)

View file

@ -23,9 +23,10 @@ import androidx.lifecycle.ViewModel
class RegistViewModel: ViewModel() class RegistViewModel: ViewModel()
{ {
enum class PS4Version { enum class PS4Version {
GE_8,
GE_7, GE_7,
LT_7 LT_7
} }
val ps4Version = MutableLiveData<PS4Version>(PS4Version.GE_7) val ps4Version = MutableLiveData<PS4Version>(PS4Version.GE_8)
} }

View file

@ -69,13 +69,22 @@
android:orientation="horizontal" android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/broadcastCheckBox"> app:layout_constraintTop_toBottomOf="@id/broadcastCheckBox">
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/ps4VersionGE8RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/regist_option_ps4_ge_8"
android:layout_weight="1"
android:checked="true"/>
<com.google.android.material.radiobutton.MaterialRadioButton <com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/ps4VersionGE7RadioButton" android:id="@+id/ps4VersionGE7RadioButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/regist_option_ps4_ge_7"
android:layout_weight="1" android:layout_weight="1"
android:checked="true"/> android:checked="false"
android:text="@string/regist_option_ps4_ge_7" />
<com.google.android.material.radiobutton.MaterialRadioButton <com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/ps4VersionLT7RadioButton" android:id="@+id/ps4VersionLT7RadioButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View file

@ -28,7 +28,8 @@
<string name="hint_regist_host">Host</string> <string name="hint_regist_host">Host</string>
<string name="regist_broadcast">Broadcast</string> <string name="regist_broadcast">Broadcast</string>
<string name="regist_option_ps4_lt_7">PS4 &lt; 7.0</string> <string name="regist_option_ps4_lt_7">PS4 &lt; 7.0</string>
<string name="regist_option_ps4_ge_7">PS4 ≥ 7.0</string> <string name="regist_option_ps4_ge_7">PS4 ≥ 7.0, &lt; 8</string>
<string name="regist_option_ps4_ge_8">PS4 ≥ 8.0</string>
<string name="regist_psn_account_id_help">About obtaining your Account ID, see</string> <string name="regist_psn_account_id_help">About obtaining your Account ID, see</string>
<string name="regist_psn_account_id_help_url">https://github.com/thestr4ng3r/chiaki/blob/master/README.md#obtaining-your-psn-accountid</string> <string name="regist_psn_account_id_help_url">https://github.com/thestr4ng3r/chiaki/blob/master/README.md#obtaining-your-psn-accountid</string>
<string name="hint_regist_psn_online_id">PSN Online ID (username, case-sensitive)</string> <string name="hint_regist_psn_online_id">PSN Online ID (username, case-sensitive)</string>

View file

@ -41,9 +41,10 @@ class RegistDialog : public QDialog
QLineEdit *host_edit; QLineEdit *host_edit;
QCheckBox *broadcast_check_box; 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; QLineEdit *psn_online_id_edit;
QRadioButton *psn_account_id_radio_button;
QLineEdit *psn_account_id_edit; QLineEdit *psn_account_id_edit;
QLineEdit *pin_edit; QLineEdit *pin_edit;
QDialogButtonBox *button_box; QDialogButtonBox *button_box;
@ -51,6 +52,8 @@ class RegistDialog : public QDialog
RegisteredHost registered_host; RegisteredHost registered_host;
bool NeedAccountId();
private slots: private slots:
void ValidateInput(); void ValidateInput();

View file

@ -59,20 +59,29 @@ RegistDialog::RegistDialog(Settings *settings, const QString &host, QWidget *par
broadcast_check_box->setChecked(host.isEmpty()); broadcast_check_box->setChecked(host.isEmpty());
auto UpdatePSNIDEdits = [this]() { auto UpdatePSNIDEdits = [this]() {
psn_online_id_edit->setEnabled(psn_online_id_radio_button->isChecked()); bool need_account_id = NeedAccountId();
psn_account_id_edit->setEnabled(psn_account_id_radio_button->isChecked()); 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); auto version_layout = new QVBoxLayout(nullptr);
psn_online_id_edit = new QLineEdit(this); ps4_pre9_radio_button = new QRadioButton(tr("< 7.0"), this);
form_layout->addRow(psn_online_id_radio_button, psn_online_id_edit); version_layout->addWidget(ps4_pre9_radio_button);
connect(psn_online_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); 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); psn_account_id_edit = new QLineEdit(this);
form_layout->addRow(psn_account_id_radio_button, psn_account_id_edit); form_layout->addRow(tr("PSN Account-ID (base64):"), psn_account_id_edit);
psn_account_id_radio_button->setChecked(true);
connect(psn_account_id_radio_button, &QRadioButton::toggled, this, UpdatePSNIDEdits); ps4_10_radio_button->setChecked(true);
UpdatePSNIDEdits(); UpdatePSNIDEdits();
@ -96,11 +105,17 @@ RegistDialog::~RegistDialog()
{ {
} }
bool RegistDialog::NeedAccountId()
{
return !ps4_pre9_radio_button->isChecked();
}
void RegistDialog::ValidateInput() void RegistDialog::ValidateInput()
{ {
bool need_account_id = NeedAccountId();
bool valid = !host_edit->text().trimmed().isEmpty() bool valid = !host_edit->text().trimmed().isEmpty()
&& (!psn_online_id_radio_button->isChecked() || !psn_online_id_edit->text().trimmed().isEmpty()) && !(!need_account_id && 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_account_id_edit->text().trimmed().isEmpty())
&& pin_edit->text().length() == PIN_LENGTH; && pin_edit->text().length() == PIN_LENGTH;
register_button->setEnabled(valid); register_button->setEnabled(valid);
} }
@ -111,8 +126,16 @@ void RegistDialog::accept()
QByteArray host = host_edit->text().trimmed().toUtf8(); QByteArray host = host_edit->text().trimmed().toUtf8();
info.host = host.constData(); 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 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(); psn_id = psn_online_id_edit->text().trimmed().toUtf8();
info.psn_online_id = psn_id.constData(); info.psn_online_id = psn_id.constData();

View file

@ -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_alloc(size_t alignment, size_t size);
CHIAKI_EXPORT void chiaki_aligned_free(void *ptr); 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 * Perform initialization of global state needed for using the Chiaki lib
*/ */

View file

@ -33,6 +33,7 @@ extern "C" {
typedef struct chiaki_regist_info_t typedef struct chiaki_regist_info_t
{ {
ChiakiTarget target;
const char *host; const char *host;
bool broadcast; 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 * @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 #ifdef __cplusplus
} }

View file

@ -31,15 +31,18 @@ extern "C" {
typedef struct chiaki_rpcrypt_t typedef struct chiaki_rpcrypt_t
{ {
ChiakiTarget target;
uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t bright[CHIAKI_RPCRYPT_KEY_SIZE];
uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE];
} ChiakiRPCrypt; } 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_bright_ambassador(ChiakiTarget target, 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_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_auth(ChiakiRPCrypt *rpcrypt, ChiakiTarget target, 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_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_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_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); CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_decrypt(ChiakiRPCrypt *rpcrypt, uint64_t counter, const uint8_t *in, uint8_t *out, size_t sz);

View file

@ -43,22 +43,16 @@ extern "C" {
#define CHIAKI_RP_APPLICATION_REASON_IN_USE 0x80108b10 #define CHIAKI_RP_APPLICATION_REASON_IN_USE 0x80108b10
#define CHIAKI_RP_APPLICATION_REASON_CRASH 0x80108b15 #define CHIAKI_RP_APPLICATION_REASON_CRASH 0x80108b15
#define CHIAKI_RP_APPLICATION_REASON_RP_VERSION 0x80108b11 #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); 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 * @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 #define CHIAKI_RP_DID_SIZE 32
@ -171,7 +165,7 @@ typedef struct chiaki_session_t
ChiakiConnectVideoProfile video_profile; ChiakiConnectVideoProfile video_profile;
} connect_info; } connect_info;
ChiakiRpVersion rp_version; ChiakiTarget target;
uint8_t nonce[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t nonce[CHIAKI_RPCRYPT_KEY_SIZE];
ChiakiRPCrypt rpcrypt; ChiakiRPCrypt rpcrypt;

View file

@ -576,9 +576,23 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl)
if(err != CHIAKI_ERR_SUCCESS) if(err != CHIAKI_ERR_SUCCESS)
goto error; 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[] = 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" "Host: %s:%d\r\n"
"User-Agent: remoteplay Windows\r\n" "User-Agent: remoteplay Windows\r\n"
"Connection: keep-alive\r\n" "Connection: keep-alive\r\n"
@ -589,17 +603,27 @@ static ChiakiErrorCode ctrl_connect(ChiakiCtrl *ctrl)
"RP-ControllerType: 3\r\n" "RP-ControllerType: 3\r\n"
"RP-ClientType: 11\r\n" "RP-ClientType: 11\r\n"
"RP-OSType: %s\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]; char buf[512];
int request_len = snprintf(buf, sizeof(buf), request_fmt, 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)) if(request_len < 0 || request_len >= sizeof(buf))
goto error; goto error;
CHIAKI_LOGI(session->log, "Sending ctrl request"); 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); int sent = send(sock, buf, (size_t)request_len, 0);
if(sent < 0) if(sent < 0)

View file

@ -106,34 +106,42 @@ static void regist_event_simple(ChiakiRegist *regist, ChiakiRegistEventType type
regist->cb(&event, regist->cb_user); regist->cb(&event, regist->cb_user);
} }
static const char * const request_head_fmt = static const char *const request_head_fmt =
"POST /sce/rp/regist HTTP/1.1\r\n" "POST %s HTTP/1.1\r\n HTTP/1.1\r\n"
"HOST: 10.0.2.15\r\n" // random lol "HOST: 10.0.2.15\r\n" // random lol
"User-Agent: remoteplay Windows\r\n" "User-Agent: remoteplay Windows\r\n"
"Connection: close\r\n" "Connection: close\r\n"
"Content-Length: %llu\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 = static const char *const request_tail = "\r\n";
"Client-Type: Windows\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"; "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" "Client-Type: Windows\r\n"
"Np-Online-Id: %s\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) if(cur < 0 || cur >= payload_size)
return -1; 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; size_t s = buf_size - cur;
int r = snprintf(buf + cur, s, request_rp_version_fmt, rp_version_str); int r = snprintf(buf + cur, s, request_rp_version_fmt, rp_version_str);
if(r < 0 || r >= s) 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; size_t buf_size_val = *buf_size;
static const size_t inner_header_off = 0x1e0; static const size_t inner_header_off = 0x1e0;
if(buf_size_val < inner_header_off) if(buf_size_val < inner_header_off)
return CHIAKI_ERR_BUF_TOO_SMALL; return CHIAKI_ERR_BUF_TOO_SMALL;
memset(buf, 'A', inner_header_off); memset(buf, 'A', inner_header_off); // can be random
chiaki_rpcrypt_aeropause(buf + 0x11c, crypt->ambassador);
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; int inner_header_size;
if(psn_online_id) 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); 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)); 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) if(err != CHIAKI_ERR_SUCCESS)
return err; 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 else
return CHIAKI_ERR_INVALID_DATA; return CHIAKI_ERR_INVALID_DATA;
@ -184,29 +212,26 @@ static void *regist_thread_func(void *user)
bool canceled = false; bool canceled = false;
bool success = false; bool success = false;
ChiakiRPCrypt crypt;
uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE]; uint8_t ambassador[CHIAKI_RPCRYPT_KEY_SIZE];
ChiakiErrorCode err = chiaki_random_bytes_crypt(ambassador, sizeof(ambassador)); ChiakiErrorCode err = chiaki_random_bytes_crypt(ambassador, sizeof(ambassador));
if(err != CHIAKI_ERR_SUCCESS) 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; goto fail;
} }
ChiakiRPCrypt crypt;
chiaki_rpcrypt_init_regist(&crypt, ambassador, regist->info.pin);
uint8_t payload[0x400]; uint8_t payload[0x400];
size_t payload_size = sizeof(payload); 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) if(err != CHIAKI_ERR_SUCCESS)
{ {
CHIAKI_LOGE(regist->log, "Regist failed to format payload"); CHIAKI_LOGE(regist->log, "Regist failed to format payload");
goto fail; goto fail;
} }
ChiakiRpVersion rp_version = regist->info.psn_online_id ? CHIAKI_RP_VERSION_8_0 : CHIAKI_RP_VERSION_9_0;
char request_header[0x100]; 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)) if(request_header_size < 0 || request_header_size >= sizeof(request_header))
{ {

View file

@ -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 }; 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 }; 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<CHIAKI_RPCRYPT_KEY_SIZE; i++)
{
uint8_t v = nonce[i];
v += 0x36;
v += i;
v ^= key[i];
ambassador[i] = v;
}
key = &static_keys_b[(nonce[7] >> 3) * 0x70];
for(size_t i=0; i<CHIAKI_RPCRYPT_KEY_SIZE; i++)
{
uint8_t v = (key[i] ^ morning[i]);
v += 0x21;
v += i;
v ^= nonce[i];
bright[i] = v;
}
}
CHIAKI_EXPORT void chiaki_rpcrypt_bright_ambassador(ChiakiTarget target, uint8_t *bright, uint8_t *ambassador, const uint8_t *nonce, const uint8_t *morning)
{
switch(target)
{
case CHIAKI_TARGET_PS4_8:
case CHIAKI_TARGET_PS4_9:
bright_ambassador_ps4_pre10(bright, ambassador, nonce, morning);
break;
default:
bright_ambassador(bright, ambassador, nonce, morning);
break;
}
}
CHIAKI_EXPORT void chiaki_rpcrypt_aeropause_ps4_pre10(uint8_t *aeropause, const uint8_t *ambassador)
{ {
for(size_t i=0; i<CHIAKI_RPCRYPT_KEY_SIZE; i++) for(size_t i=0; i<CHIAKI_RPCRYPT_KEY_SIZE; i++)
{ {
@ -67,14 +828,81 @@ CHIAKI_EXPORT void chiaki_rpcrypt_aeropause(uint8_t *aeropause, const uint8_t *a
} }
} }
CHIAKI_EXPORT void chiaki_rpcrypt_init_auth(ChiakiRPCrypt *rpcrypt, const uint8_t *nonce, const uint8_t *morning) CHIAKI_EXPORT void chiaki_rpcrypt_aeropause(size_t key_1_off, uint8_t *aeropause, const uint8_t *ambassador)
{ {
chiaki_rpcrypt_bright_ambassador(rpcrypt->bright, 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; i<CHIAKI_RPCRYPT_KEY_SIZE; i++)
{
uint8_t k = keys_1[i*0x20 + key_1_off];
aeropause[i] = (ambassador[i] ^ k) + 0x29 + (uint8_t)i;
}
} }
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)
{ {
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 }; rpcrypt->target = 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->ambassador, ambassador, sizeof(rpcrypt->ambassador));
memcpy(rpcrypt->bright, regist_aes_key, sizeof(rpcrypt->bright)); memcpy(rpcrypt->bright, regist_aes_key, sizeof(rpcrypt->bright));
rpcrypt->bright[0] ^= (uint8_t)((pin >> 0x18) & 0xff); 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); 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; i<CHIAKI_RPCRYPT_KEY_SIZE; i++)
rpcrypt->bright[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 #ifdef CHIAKI_LIB_ENABLE_MBEDTLS
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, uint8_t *iv, uint64_t counter) 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]; uint8_t buf[CHIAKI_RPCRYPT_KEY_SIZE + 8];
memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE); memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE);
@ -114,7 +1033,7 @@ CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt,
} while(0) } while(0)
// https://tls.mbed.org/module-level-design-hashing // 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_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_update(&ctx, (const unsigned char *) buf, sizeof(buf)));
GOTO_ERROR(mbedtls_md_hmac_finish(&ctx, hmac)); GOTO_ERROR(mbedtls_md_hmac_finish(&ctx, hmac));
#undef GOTO_ERROR #undef GOTO_ERROR
@ -172,7 +1091,7 @@ error:
#else #else
CHIAKI_EXPORT ChiakiErrorCode chiaki_rpcrypt_generate_iv(ChiakiRPCrypt *rpcrypt, uint8_t *iv, uint64_t counter) 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]; uint8_t buf[CHIAKI_RPCRYPT_KEY_SIZE + 8];
memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE); memcpy(buf, rpcrypt->ambassador, CHIAKI_RPCRYPT_KEY_SIZE);

View file

@ -46,7 +46,7 @@
#define SESSION_EXPECT_TIMEOUT_MS 5000 #define SESSION_EXPECT_TIMEOUT_MS 5000
static void *session_thread_func(void *arg); 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) 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) switch(version)
{ {
case CHIAKI_RP_VERSION_8_0: case CHIAKI_TARGET_PS4_8:
return "8.0"; return "8.0";
case CHIAKI_RP_VERSION_9_0: case CHIAKI_TARGET_PS4_9:
return "9.0"; return "9.0";
case CHIAKI_TARGET_PS4_10:
return "10.0";
default: default:
return NULL; 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) 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) if(strcmp(rp_version_str, "9.0") == 0)
return CHIAKI_RP_VERSION_9_0; return CHIAKI_TARGET_PS4_9;
return CHIAKI_RP_VERSION_UNKNOWN; 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) 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->log = log;
session->quit_reason = CHIAKI_QUIT_REASON_NONE; 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); ChiakiErrorCode err = chiaki_cond_init(&session->state_cond);
if(err != CHIAKI_ERR_SUCCESS) if(err != CHIAKI_ERR_SUCCESS)
@ -369,13 +373,20 @@ static void *session_thread_func(void *arg)
CHIAKI_LOGI(session->log, "Starting session request"); CHIAKI_LOGI(session->log, "Starting session request");
ChiakiRpVersion server_rp_version = CHIAKI_RP_VERSION_UNKNOWN; ChiakiTarget server_target = CHIAKI_TARGET_PS4_UNKNOWN;
success = session_thread_request_session(session, &server_rp_version); 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"); 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); 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_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 // 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); 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; chiaki_socket_t session_sock = CHIAKI_INVALID_SOCKET;
for(struct addrinfo *ai=session->connect_info.host_addrinfos; ai; ai=ai->ai_next) 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); CHIAKI_LOGI(session->log, "Connected to %s:%d", session->connect_info.hostname, SESSION_PORT);
static const char session_request_fmt[] = 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" "Host: %s:%d\r\n"
"User-Agent: remoteplay Windows\r\n" "User-Agent: remoteplay Windows\r\n"
"Connection: close\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-Registkey: %s\r\n"
"Rp-Version: %s\r\n" "Rp-Version: %s\r\n"
"\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); size_t regist_key_len = sizeof(session->connect_info.regist_key);
for(size_t i=0; i<regist_key_len; i++) for(size_t i=0; i<regist_key_len; i++)
@ -703,11 +717,11 @@ static bool session_thread_request_session(ChiakiSession *session, ChiakiRpVersi
return false; return false;
} }
const char *rp_version_str = chiaki_rp_version_string(session->rp_version); const char *rp_version_str = chiaki_rp_version_string(session->target);
char buf[512]; char buf[512];
int request_len = snprintf(buf, sizeof(buf), session_request_fmt, 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)) if(request_len < 0 || request_len >= sizeof(buf))
{ {
CHIAKI_SOCKET_CLOSE(session_sock); 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; 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); CHIAKI_LOGI(session->log, "Reported RP-Version mismatch. ours = %s, server = %s",
*server_version_out = chiaki_rp_version_parse(response.rp_version); rp_version_str ? rp_version_str : "", response.rp_version);
if(*server_version_out != CHIAKI_RP_VERSION_UNKNOWN) *target_out = chiaki_rp_version_parse(response.rp_version);
CHIAKI_LOGI(session->log, "Detected Server RP-Version %s", chiaki_rp_version_string(*server_version_out)); 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 else
{ {
CHIAKI_LOGE(session->log, "Server RP-Version is unknown"); CHIAKI_LOGE(session->log, "Server RP-Version is unknown");

View file

@ -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 uint32_t pin = 13374201;
static const char * const psn_id = "ChiakiNanami1337"; 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 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]; 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); munit_assert_memory_equal(sizeof(expected), aeropause, expected);
return MUNIT_OK; 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 }; 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; 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); munit_assert_memory_equal(sizeof(expected), rpcrypt.bright, expected);
return MUNIT_OK; 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[] = { 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, 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; ChiakiRPCrypt rpcrypt;
chiaki_rpcrypt_init_regist(&rpcrypt, ambassador, pin);
uint8_t payload[0x400]; uint8_t payload[0x400];
size_t payload_size = sizeof(payload); 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_int(err, ==, CHIAKI_ERR_SUCCESS);
munit_assert_size(payload_size, ==, sizeof(expected)); munit_assert_size(payload_size, ==, sizeof(expected));
munit_assert_memory_equal(sizeof(expected), payload, expected); munit_assert_memory_equal(sizeof(expected), payload, expected);
@ -78,24 +77,24 @@ static MunitResult test_request_payload(const MunitParameter params[], void *use
MunitTest tests_regist[] = { MunitTest tests_regist[] = {
{ {
"/aeropause", "/aeropause_ps4_pre10",
test_aeropause, test_aeropause_ps4_pre10,
NULL, NULL,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,
NULL NULL
}, },
{ {
"/pin_bright", "/pin_bright_ps4_pre10",
test_pin_bright, test_pin_bright_ps4_pre10,
NULL, NULL,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,
NULL NULL
}, },
{ {
"/request_payload", "/request_payload_ps4_pre10",
test_request_payload, test_request_payload_ps4_pre10,
NULL, NULL,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,

View file

@ -19,19 +19,16 @@
#include <chiaki/rpcrypt.h> #include <chiaki/rpcrypt.h>
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 MunitResult test_bright_ambassador(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 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 }; 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 bright[CHIAKI_RPCRYPT_KEY_SIZE];
uint8_t ambassador[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, bright, bright_expected);
munit_assert_memory_equal(CHIAKI_RPCRYPT_KEY_SIZE, ambassador, ambassador_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; 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_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 }; 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; ChiakiRPCrypt rpcrypt;
ChiakiErrorCode err; 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]; uint8_t iv[CHIAKI_RPCRYPT_KEY_SIZE];
@ -74,14 +90,49 @@ static MunitResult test_iv(const MunitParameter params[], void *user)
return MUNIT_OK; return MUNIT_OK;
} }
#include <stdio.h> static MunitResult test_iv_regist(const MunitParameter params[], void *user)
static MunitResult test_encrypt(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; ChiakiRPCrypt rpcrypt;
ChiakiErrorCode err; 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 // less than block size
uint8_t buf_a[] = { 0x13, 0x37, 0xc0, 0xff, 0xee }; 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; 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; ChiakiRPCrypt rpcrypt;
ChiakiErrorCode err; ChiakiErrorCode err;
chiaki_rpcrypt_init_auth(&rpcrypt, nonce, morning); chiaki_rpcrypt_init_auth(&rpcrypt, CHIAKI_TARGET_PS4_9, nonce, morning);
// less than block size // less than block size
uint8_t buf_a[] = { 0x8d, 0xd2, 0x1d, 0xfb }; uint8_t buf_a[] = { 0x8d, 0xd2, 0x1d, 0xfb };
@ -162,6 +215,14 @@ static MunitResult test_decrypt(const MunitParameter params[], void *user)
MunitTest tests_rpcrypt[] = { MunitTest tests_rpcrypt[] = {
{
"/bright_ambassador_ps4_pre10",
test_bright_ambassador_ps4_pre10,
NULL,
NULL,
MUNIT_TEST_OPTION_NONE,
NULL
},
{ {
"/bright_ambassador", "/bright_ambassador",
test_bright_ambassador, test_bright_ambassador,
@ -171,24 +232,40 @@ MunitTest tests_rpcrypt[] = {
NULL NULL
}, },
{ {
"/iv", "/iv_ps4_pre10",
test_iv, test_iv_ps4_pre10,
NULL, NULL,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,
NULL NULL
}, },
{ {
"/encrypt", "/iv_regist",
test_encrypt, test_iv_regist,
NULL, NULL,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,
NULL NULL
}, },
{ {
"/decrypt", "/bright_regist",
test_decrypt, 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,
NULL, NULL,
MUNIT_TEST_OPTION_NONE, MUNIT_TEST_OPTION_NONE,