diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc index 812d1e035..309044514 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc @@ -29,6 +29,7 @@ #include "third_party/crypto/sha256.h" extern "C" { +#include "third_party/FFmpeg/libavutil/md5.h" #include "third_party/FFmpeg/libavutil/sha512.h" #include "third_party/aes_128/aes.h" } @@ -168,6 +169,33 @@ void XeCryptSha_entry(lpvoid_t input_1, dword_t input_1_size, lpvoid_t input_2, } DECLARE_XBOXKRNL_EXPORT1(XeCryptSha, kNone, kImplemented); +void XeCryptMd5_entry(lpvoid_t input_1, dword_t input_1_size, lpvoid_t input_2, + dword_t input_2_size, lpvoid_t input_3, + dword_t input_3_size, lpvoid_t output, + dword_t output_size) { + AVMD5* md5 = av_md5_alloc(); + av_md5_init(md5); + + if (input_1 && input_1_size) { + av_md5_update(md5, input_1, input_1_size); + } + + if (input_2 && input_2_size) { + av_md5_update(md5, input_2, input_2_size); + } + + if (input_3 && input_3_size) { + av_md5_update(md5, input_3, input_3_size); + } + + uint8_t digest[16]; + av_md5_final(md5, digest); + + std::copy_n(digest, std::min(xe::countof(digest), output_size), + output.as()); +} +DECLARE_XBOXKRNL_EXPORT1(XeCryptMd5, kNone, kImplemented); + // TODO: Size of this struct hasn't been confirmed yet. typedef struct { xe::be count; // 0x0 @@ -299,6 +327,77 @@ void XeCryptSha512Final_entry(pointer_t sha_state, } DECLARE_XBOXKRNL_EXPORT1(XeCryptSha512Final, kNone, kImplemented); +// TODO: Size of this struct hasn't been confirmed yet. +typedef struct { + xe::be count; + xe::be state[4]; + uint8_t buffer[64]; +} XECRYPT_MD5_STATE; + +void XeCryptMd5Init_entry(pointer_t md5_state) { + md5_state.Zero(); + + // must match av_md5_init + md5_state->state[0] = 0x10325476; + md5_state->state[1] = 0x98badcfe; + md5_state->state[2] = 0xefcdab89; + md5_state->state[3] = 0x67452301; +} +DECLARE_XBOXKRNL_EXPORT1(XeCryptMd5Init, kNone, kImplemented); + +struct MD5_STATE { + uint64_t len; + uint8_t block[64]; + uint32_t ABCD[4]; +}; + +void XeCryptMd5Update_entry(pointer_t md5_state, + lpvoid_t input, dword_t input_size) { + AVMD5* md5 = av_md5_alloc(); + av_md5_init(md5); + + // Trick to make similar implementation as SHA256 + MD5_STATE* md5InternalState = reinterpret_cast(md5); + std::copy(std::begin(md5_state->state), std::end(md5_state->state), + md5InternalState->ABCD); + std::copy(std::begin(md5_state->buffer), std::end(md5_state->buffer), + md5InternalState->block); + md5InternalState->len = md5_state->count; + + // Add new entry from input + av_md5_update(md5, input, input_size); + + // Copy back data to guest md5_state + std::copy_n(md5InternalState->ABCD, xe::countof(md5_state->state), + md5_state->state); + std::copy_n(md5InternalState->block, xe::countof(md5_state->buffer), + md5_state->buffer); + md5_state->count = md5InternalState->len; +} +DECLARE_XBOXKRNL_EXPORT1(XeCryptMd5Update, kNone, kImplemented); + +void XeCryptMd5Final_entry(pointer_t md5_state, + pointer_t out, dword_t out_size) { + AVMD5* md5 = av_md5_alloc(); + av_md5_init(md5); + + // Trick to make similar implementation as SHA256 + MD5_STATE* md5InternalState = reinterpret_cast(md5); + std::copy(std::begin(md5_state->state), std::end(md5_state->state), + md5InternalState->ABCD); + std::copy(std::begin(md5_state->buffer), std::end(md5_state->buffer), + md5InternalState->block); + md5InternalState->len = md5_state->count; + + uint8_t hash[16]; + av_md5_final(md5, hash); + + std::copy_n(hash, std::min(xe::countof(hash), out_size), + static_cast(out)); + std::copy(std::begin(hash), std::end(hash), md5_state->buffer); +} +DECLARE_XBOXKRNL_EXPORT1(XeCryptMd5Final, kNone, kImplemented); + // Byteswaps each 8 bytes void XeCryptBnQw_SwapDwQwLeBe_entry(pointer_t qw_inp, pointer_t qw_out, dword_t size) {