diff --git a/src/xenia/kernel/util/crypto_utils.cc b/src/xenia/kernel/util/crypto_utils.cc new file mode 100644 index 000000000..9c08441cf --- /dev/null +++ b/src/xenia/kernel/util/crypto_utils.cc @@ -0,0 +1,130 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ +#include + +#include "xenia/kernel/util/crypto_utils.h" +#include "xenia/xbox.h" + +#include "third_party/crypto/TinySHA1.hpp" + +namespace xe { +namespace kernel { +namespace util { + +uint8_t xekey_0x19[] = {0xE1, 0xBC, 0x15, 0x9C, 0x73, 0xB1, 0xEA, 0xE9, + 0xAB, 0x31, 0x70, 0xF3, 0xAD, 0x47, 0xEB, 0xF3}; + +uint8_t xekey_0x19_devkit[] = {0xDA, 0xB6, 0x9A, 0xD9, 0x8E, 0x28, 0x76, 0x4F, + 0x97, 0x7E, 0xE2, 0x48, 0x7E, 0x4F, 0x3F, 0x68}; + +const uint8_t* GetXeKey(uint32_t idx, bool devkit) { + if (idx != 0x19) { + return nullptr; + } + + return devkit ? xekey_0x19_devkit : xekey_0x19; +} + +void HmacSha(const uint8_t* key, uint32_t key_size_in, const uint8_t* inp_1, + uint32_t inp_1_size, const uint8_t* inp_2, uint32_t inp_2_size, + const uint8_t* inp_3, uint32_t inp_3_size, uint8_t* out, + uint32_t out_size) { + uint32_t key_size = key_size_in; + sha1::SHA1 sha; + uint8_t kpad_i[0x40]; + uint8_t kpad_o[0x40]; + uint8_t tmp_key[0x40]; + std::memset(kpad_i, 0x36, 0x40); + std::memset(kpad_o, 0x5C, 0x40); + + // Setup HMAC key + // If > block size, use its hash + if (key_size > 0x40) { + sha1::SHA1 sha_key; + sha_key.processBytes(key, key_size); + sha_key.finalize((uint8_t*)tmp_key); + + key_size = 0x14u; + } else { + std::memcpy(tmp_key, key, key_size); + } + + for (uint32_t i = 0; i < key_size; i++) { + kpad_i[i] = tmp_key[i] ^ 0x36; + kpad_o[i] = tmp_key[i] ^ 0x5C; + } + + // Inner + sha.processBytes(kpad_i, 0x40); + + if (inp_1_size) { + sha.processBytes(inp_1, inp_1_size); + } + + if (inp_2_size) { + sha.processBytes(inp_2, inp_2_size); + } + + if (inp_3_size) { + sha.processBytes(inp_3, inp_3_size); + } + + uint8_t digest[0x14]; + sha.finalize(digest); + sha.reset(); + + // Outer + sha.processBytes(kpad_o, 0x40); + sha.processBytes(digest, 0x14); + sha.finalize(digest); + + std::memcpy(out, digest, std::min((uint32_t)out_size, 0x14u)); +} + +void RC4(const uint8_t* key, uint32_t key_size_in, const uint8_t* data, + uint32_t data_size, uint8_t* out, uint32_t out_size) { + uint8_t tmp_key[0x10]; + uint32_t sbox_size; + uint8_t sbox[0x100]; + uint32_t i; + uint32_t j; + + // Setup RC4 session... + std::memcpy(tmp_key, key, 0x10); + i = j = 0; + sbox_size = 0x100; + for (uint32_t x = 0; x < sbox_size; x++) { + sbox[x] = (uint8_t)x; + } + + uint32_t idx = 0; + for (uint32_t x = 0; x < sbox_size; x++) { + idx = (idx + sbox[x] + key[x % 0x10]) % sbox_size; + uint8_t temp = sbox[idx]; + sbox[idx] = sbox[x]; + sbox[x] = temp; + } + + // Crypt data + for (uint32_t idx = 0; idx < data_size; idx++) { + i = (i + 1) % sbox_size; + j = (j + sbox[i]) % sbox_size; + uint8_t temp = sbox[i]; + sbox[i] = sbox[j]; + sbox[j] = temp; + + uint8_t a = data[idx]; + uint8_t b = sbox[(sbox[i] + sbox[j]) % sbox_size]; + out[idx] = (uint8_t)(a ^ b); + } +} + +} // namespace util +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/util/crypto_utils.h b/src/xenia/kernel/util/crypto_utils.h new file mode 100644 index 000000000..456b7cff7 --- /dev/null +++ b/src/xenia/kernel/util/crypto_utils.h @@ -0,0 +1,28 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/xbox.h" + +namespace xe { +namespace kernel { +namespace util { + +const uint8_t* GetXeKey(uint32_t idx, bool devkit = false); + +void HmacSha(const uint8_t* key, uint32_t key_size_in, const uint8_t* inp_1, + uint32_t inp_1_size, const uint8_t* inp_2, uint32_t inp_2_size, + const uint8_t* inp_3, uint32_t inp_3_size, uint8_t* out, + uint32_t out_size); + +void RC4(const uint8_t* key, uint32_t key_size_in, const uint8_t* data, + uint32_t data_size, uint8_t* out, uint32_t out_size); + +} // namespace util +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc index 3d78e5b48..507dc6860 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc @@ -9,6 +9,7 @@ #include "xenia/base/logging.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/util/crypto_utils.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/xbox.h" @@ -428,75 +429,17 @@ void XeCryptHmacSha(lpvoid_t key, dword_t key_size_in, lpvoid_t inp_1, dword_t inp_1_size, lpvoid_t inp_2, dword_t inp_2_size, lpvoid_t inp_3, dword_t inp_3_size, lpvoid_t out, dword_t out_size) { - uint32_t key_size = key_size_in; - sha1::SHA1 sha; - uint8_t kpad_i[0x40]; - uint8_t kpad_o[0x40]; - uint8_t tmp_key[0x40]; - std::memset(kpad_i, 0x36, 0x40); - std::memset(kpad_o, 0x5C, 0x40); - - // Setup HMAC key - // If > block size, use its hash - if (key_size > 0x40) { - sha1::SHA1 sha_key; - sha_key.processBytes(key, key_size); - sha_key.finalize((uint8_t*)tmp_key); - - key_size = 0x14u; - } else { - std::memcpy(tmp_key, key, key_size); - } - - for (uint32_t i = 0; i < key_size; i++) { - kpad_i[i] = tmp_key[i] ^ 0x36; - kpad_o[i] = tmp_key[i] ^ 0x5C; - } - - // Inner - sha.processBytes(kpad_i, 0x40); - - if (inp_1_size) { - sha.processBytes(inp_1, inp_1_size); - } - - if (inp_2_size) { - sha.processBytes(inp_2, inp_2_size); - } - - if (inp_3_size) { - sha.processBytes(inp_3, inp_3_size); - } - - uint8_t digest[0x14]; - sha.finalize(digest); - sha.reset(); - - // Outer - sha.processBytes(kpad_o, 0x40); - sha.processBytes(digest, 0x14); - sha.finalize(digest); - - std::memcpy(out, digest, std::min((uint32_t)out_size, 0x14u)); + util::HmacSha(key, key_size_in, inp_1, inp_1_size, inp_2, inp_2_size, inp_3, + inp_3_size, out, out_size); } DECLARE_XBOXKRNL_EXPORT1(XeCryptHmacSha, kNone, kImplemented); -// Keys -// TODO: Array of keys we need - -// Retail key 0x19 -static const uint8_t key19[] = {0xE1, 0xBC, 0x15, 0x9C, 0x73, 0xB1, 0xEA, 0xE9, - 0xAB, 0x31, 0x70, 0xF3, 0xAD, 0x47, 0xEB, 0xF3}; - dword_result_t XeKeysHmacSha(dword_t key_num, lpvoid_t inp_1, dword_t inp_1_size, lpvoid_t inp_2, dword_t inp_2_size, lpvoid_t inp_3, dword_t inp_3_size, lpvoid_t out, dword_t out_size) { - const uint8_t* key = nullptr; - if (key_num == 0x19) { - key = key19; - } + const uint8_t* key = util::GetXeKey(key_num); if (key) { XeCryptHmacSha((void*)key, 0x10, inp_1, inp_1_size, inp_2, inp_2_size,