From fb87b7a3c3eacf5edf2aac4e74a473fc55a6ffaf Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Mon, 11 Jul 2016 10:34:33 -0500 Subject: [PATCH] xboxkrnl: Add a bunch of crypto functions --- src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc | 232 +++++++- third_party/crypto/des/LICENSE | 22 + third_party/crypto/des/README.md | 6 + third_party/crypto/des/des.cpp | 177 ++++++ third_party/crypto/des/des.h | 51 ++ third_party/crypto/des/des3.h | 40 ++ third_party/crypto/des/des_data.h | 121 ++++ third_party/crypto/des/des_key.h | 38 ++ third_party/crypto/des/des_lookup.h | 4 + third_party/crypto/des/descbc.h | 34 ++ third_party/crypto/rc4.c | 90 +++ third_party/crypto/rc4.h | 50 ++ third_party/crypto/sha256.cpp | 576 ++++++++++++++++++++ third_party/crypto/sha256.h | 79 +++ 14 files changed, 1506 insertions(+), 14 deletions(-) create mode 100644 third_party/crypto/des/LICENSE create mode 100644 third_party/crypto/des/README.md create mode 100644 third_party/crypto/des/des.cpp create mode 100644 third_party/crypto/des/des.h create mode 100644 third_party/crypto/des/des3.h create mode 100644 third_party/crypto/des/des_data.h create mode 100644 third_party/crypto/des/des_key.h create mode 100644 third_party/crypto/des/des_lookup.h create mode 100644 third_party/crypto/des/descbc.h create mode 100644 third_party/crypto/rc4.c create mode 100644 third_party/crypto/rc4.h create mode 100644 third_party/crypto/sha256.cpp create mode 100644 third_party/crypto/sha256.h diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc index 170a59781..df0d4361f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_crypt.cc @@ -14,6 +14,12 @@ #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "third_party/crypto/TinySHA1.hpp" +#include "third_party/crypto/des/des.cpp" +#include "third_party/crypto/des/des.h" +#include "third_party/crypto/des/des3.h" +#include "third_party/crypto/des/descbc.h" +#include "third_party/crypto/sha256.cpp" +#include "third_party/crypto/sha256.h" namespace xe { namespace kernel { @@ -70,22 +76,17 @@ void XeCryptShaFinal(pointer_t sha_state, sha1::SHA1 sha; InitSha1(&sha, sha_state); - uint32_t digest[5]; + uint8_t digest[0x14]; sha.finalize(digest); - for (int i = 0; i < 5; i++) { - sha_state->state[i] = digest[i]; - } - - for (uint32_t i = 0; i < out_size / 4; i++) { - out[i] = digest[i]; - } + std::memcpy(out, digest, std::min((uint32_t)out_size, 0x14u)); + std::memcpy(sha_state->state, digest, 0x14); } DECLARE_XBOXKRNL_EXPORT(XeCryptShaFinal, ExportTag::kImplemented); void XeCryptSha(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, - pointer_t> output, dword_t output_size) { + lpvoid_t output, dword_t output_size) { sha1::SHA1 sha; if (input_1 && input_1_size) { @@ -98,15 +99,63 @@ void XeCryptSha(lpvoid_t input_1, dword_t input_1_size, lpvoid_t input_2, sha.processBytes(input_3, input_3_size); } - uint32_t digest[5]; + uint8_t digest[0x14]; sha.finalize(digest); - - for (uint32_t i = 0; i < output_size / 4; i++) { - output[i] = digest[i]; - } + std::memcpy(output, digest, std::min((uint32_t)output_size, 0x14u)); } DECLARE_XBOXKRNL_EXPORT(XeCryptSha, ExportTag::kImplemented); +// TODO: Size of this struct hasn't been confirmed yet. +typedef struct { + xe::be count; // 0x0 + xe::be state[8]; // 0x4 + uint8_t buffer[64]; // 0x24 +} XECRYPT_SHA256_STATE; + +void XeCryptSha256Init(pointer_t sha_state) { + sha_state.Zero(); + + sha_state->state[0] = 0x6a09e667; + sha_state->state[1] = 0xbb67ae85; + sha_state->state[2] = 0x3c6ef372; + sha_state->state[3] = 0xa54ff53a; + sha_state->state[4] = 0x510e527f; + sha_state->state[5] = 0x9b05688c; + sha_state->state[6] = 0x1f83d9ab; + sha_state->state[7] = 0x5be0cd19; +} +DECLARE_XBOXKRNL_EXPORT(XeCryptSha256Init, ExportTag::kStub); + +void XeCryptSha256Update(pointer_t sha_state, + lpvoid_t input, dword_t input_size) { + sha256::SHA256 sha; + std::memcpy(sha.getHashValues(), sha_state->state, 8 * 4); + std::memcpy(sha.getBuffer(), sha_state->buffer, 64); + sha.setTotalSize(sha_state->count); + + sha.add(input, input_size); + + std::memcpy(sha_state->state, sha.getHashValues(), 8 * 4); + std::memcpy(sha_state->buffer, sha.getBuffer(), 64); + sha_state->count = uint32_t(sha.getTotalSize()); +} +DECLARE_XBOXKRNL_EXPORT(XeCryptSha256Update, ExportTag::kStub); + +void XeCryptSha256Final(pointer_t sha_state, + pointer_t> out, dword_t out_size) { + sha256::SHA256 sha; + std::memcpy(sha.getHashValues(), sha_state->state, 8 * 4); + std::memcpy(sha.getBuffer(), sha_state->buffer, 64); + sha.setTotalSize(sha_state->count); + + uint32_t hash[8]; + sha.getHash(reinterpret_cast(hash)); + + std::memcpy(out, hash, std::min(uint32_t(out_size), 32u)); + std::memcpy(sha_state->buffer, hash, 32); +} +DECLARE_XBOXKRNL_EXPORT(XeCryptSha256Final, ExportTag::kStub); + // Byteswap? dword_result_t XeCryptBnQw_SwapDwQwLeBe(lpqword_t qw_inp, lpqword_t qw_out, dword_t size) { @@ -128,6 +177,161 @@ dword_result_t XeCryptBnDwLePkcs1Verify(lpvoid_t hash, lpvoid_t sig, } DECLARE_XBOXKRNL_EXPORT(XeCryptBnDwLePkcs1Verify, ExportTag::kStub); +void XeCryptRandom(lpvoid_t buf, dword_t buf_size) { + std::memset(buf, 0xFD, buf_size); +} +DECLARE_XBOXKRNL_EXPORT(XeCryptRandom, ExportTag::kStub); + +struct XECRYPT_DES_STATE { + uint32_t keytab[16][2]; +}; + +// Sets bit 0 to make the parity odd +void XeCryptDesParity(lpvoid_t inp, dword_t inp_size, lpvoid_t out_ptr) { + DES::set_parity(inp, inp_size, out_ptr); +} +DECLARE_XBOXKRNL_EXPORT(XeCryptDesParity, ExportTag::kImplemented); + +struct XECRYPT_DES3_STATE { + XECRYPT_DES_STATE des_state[3]; +}; + +void XeCryptDes3Key(pointer_t state_ptr, lpqword_t key) { + DES3 des3(key[0], key[1], key[2]); + DES* des = des3.getDES(); + + // Store our DES state into the state. + for (int i = 0; i < 3; i++) { + std::memcpy(state_ptr->des_state[i].keytab, des[i].get_sub_key(), 128); + } +} +DECLARE_XBOXKRNL_EXPORT(XeCryptDes3Key, ExportTag::kImplemented); + +void XeCryptDes3Ecb(pointer_t state_ptr, lpqword_t inp, + lpqword_t out, dword_t encrypt) { + DES3 des3((ui64*)state_ptr->des_state[0].keytab, + (ui64*)state_ptr->des_state[1].keytab, + (ui64*)state_ptr->des_state[2].keytab); + + if (encrypt) { + *out = des3.encrypt(*inp); + } else { + *out = des3.decrypt(*inp); + } +} +DECLARE_XBOXKRNL_EXPORT(XeCryptDes3Ecb, ExportTag::kImplemented); + +void XeCryptDes3Cbc(pointer_t state_ptr, lpqword_t inp, + dword_t inp_size, lpqword_t out, lpqword_t feed, + dword_t encrypt) { + DES3 des3((ui64*)state_ptr->des_state[0].keytab, + (ui64*)state_ptr->des_state[1].keytab, + (ui64*)state_ptr->des_state[2].keytab); + + // DES can only do 8-byte chunks at a time! + assert_true(inp_size % 8 == 0); + + uint64_t last_block = *feed; + for (uint32_t i = 0; i < inp_size / 8; i++) { + uint64_t block = inp[i]; + if (encrypt) { + last_block = des3.encrypt(block ^ last_block); + out[i] = last_block; + } else { + out[i] = des3.decrypt(block) ^ last_block; + last_block = block; + } + } + + *feed = last_block; +} +DECLARE_XBOXKRNL_EXPORT(XeCryptDes3Cbc, ExportTag::kImplemented); + +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)); +} +DECLARE_XBOXKRNL_EXPORT(XeCryptHmacSha, ExportTag::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; + } + + if (key) { + XeCryptHmacSha((void*)key, 0x10, inp_1, inp_1_size, inp_2, inp_2_size, + inp_3, inp_3_size, out, out_size); + + return X_STATUS_SUCCESS; + } + + return X_STATUS_UNSUCCESSFUL; +} +DECLARE_XBOXKRNL_EXPORT(XeKeysHmacSha, ExportTag::kStub); + void RegisterCryptExports(xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) {} diff --git a/third_party/crypto/des/LICENSE b/third_party/crypto/des/LICENSE new file mode 100644 index 000000000..45e37f528 --- /dev/null +++ b/third_party/crypto/des/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Faraz Fallahi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/third_party/crypto/des/README.md b/third_party/crypto/des/README.md new file mode 100644 index 000000000..c904a2894 --- /dev/null +++ b/third_party/crypto/des/README.md @@ -0,0 +1,6 @@ +cppDES +====== + +Taken from [this repository](https://github.com/fffaraz/cppDES) + +Modified for use by Xenia. \ No newline at end of file diff --git a/third_party/crypto/des/des.cpp b/third_party/crypto/des/des.cpp new file mode 100644 index 000000000..d4ad544b1 --- /dev/null +++ b/third_party/crypto/des/des.cpp @@ -0,0 +1,177 @@ +#include "des.h" +#include "des_key.h" +#include "des_data.h" +#include "des_lookup.h" + +#include + +//#pragma GCC push_options +#ifndef _MSC_VER +#pragma GCC optimize ("unroll-loops") +#endif + +DES::DES(ui64 key) +{ + keygen(key); +} + +DES::DES(ui64* sub_key) +{ + set_sub_key(sub_key); +} + +void DES::set_sub_key(ui64 *sub_key) +{ + std::memcpy(this->sub_key, sub_key, 128); +} + +ui64 DES::encrypt(ui64 block) +{ + return des(block, false); +} + +ui64 DES::decrypt(ui64 block) +{ + return des(block, true); +} + +ui64 DES::encrypt(ui64 block, ui64 key) +{ + DES des(key); + return des.des(block, false); +} + +ui64 DES::decrypt(ui64 block, ui64 key) +{ + DES des(key); + return des.des(block, true); +} + +void DES::keygen(ui64 key) +{ + // initial key schedule calculation + ui64 permuted_choice_1 = 0; // 56 bits + for (ui8 i = 0; i < 56; i++) + { + permuted_choice_1 <<= 1; + permuted_choice_1 |= (key >> (64-PC1[i])) & LB64_MASK; + } + + // 28 bits + ui32 C = (ui32) ((permuted_choice_1 >> 28) & 0x000000000fffffff); + ui32 D = (ui32) (permuted_choice_1 & 0x000000000fffffff); + + // Calculation of the 16 keys + for (ui8 i = 0; i < 16; i++) + { + // key schedule, shifting Ci and Di + for (ui8 j = 0; j < ITERATION_SHIFT[i]; j++) + { + C = (0x0fffffff & (C << 1)) | (0x00000001 & (C >> 27)); + D = (0x0fffffff & (D << 1)) | (0x00000001 & (D >> 27)); + } + + ui64 permuted_choice_2 = (((ui64) C) << 28) | (ui64) D; + + sub_key[i] = 0; // 48 bits (2*24) + for (ui8 j = 0; j < 48; j++) + { + sub_key[i] <<= 1; + sub_key[i] |= (permuted_choice_2 >> (56-PC2[j])) & LB64_MASK; + } + } +} + +ui64 DES::des(ui64 block, bool mode) +{ + // applying initial permutation + block = ip(block); + + // dividing T' into two 32-bit parts + ui32 L = (ui32) (block >> 32) & L64_MASK; + ui32 R = (ui32) (block & L64_MASK); + + // 16 rounds + for (ui8 i = 0; i < 16; i++) + { + ui32 F = mode ? f(R, sub_key[15-i]) : f(R, sub_key[i]); + feistel(L, R, F); + } + + // swapping the two parts + block = (((ui64) R) << 32) | (ui64) L; + // applying final permutation + return fp(block); +} + +ui64 DES::ip(ui64 block) +{ + // initial permutation + ui64 result = 0; + for (ui8 i = 0; i < 64; i++) + { + result <<= 1; + result |= (block >> (64-IP[i])) & LB64_MASK; + } + return result; +} + +ui64 DES::fp(ui64 block) +{ + // inverse initial permutation + ui64 result = 0; + for (ui8 i = 0; i < 64; i++) + { + result <<= 1; + result |= (block >> (64-FP[i])) & LB64_MASK; + } + return result; +} + +void DES::feistel(ui32 &L, ui32 &R, ui32 F) +{ + ui32 temp = R; + R = L ^ F; + L = temp; +} + +ui32 DES::f(ui32 R, ui64 k) // f(R,k) function +{ + // applying expansion permutation and returning 48-bit data + ui64 s_input = 0; + for (ui8 i = 0; i < 48; i++) + { + s_input <<= 1; + s_input |= (ui64) ((R >> (32-EXPANSION[i])) & LB32_MASK); + } + + // XORing expanded Ri with Ki, the round key + s_input = s_input ^ k; + + // applying S-Boxes function and returning 32-bit data + ui32 s_output = 0; + for (ui8 i = 0; i < 8; i++) + { + // Outer bits + char row = (char) ((s_input & (0x0000840000000000 >> 6*i)) >> (42-6*i)); + row = (row >> 4) | (row & 0x01); + + // Middle 4 bits of input + char column = (char) ((s_input & (0x0000780000000000 >> 6*i)) >> (43-6*i)); + + s_output <<= 4; + s_output |= (ui32) (SBOX[i][16*row + column] & 0x0f); + } + + // applying the round permutation + ui32 f_result = 0; + for (ui8 i = 0; i < 32; i++) + { + f_result <<= 1; + f_result |= (s_output >> (32 - PBOX[i])) & LB32_MASK; + } + + return f_result; +} + +//#pragma GCC pop_options diff --git a/third_party/crypto/des/des.h b/third_party/crypto/des/des.h new file mode 100644 index 000000000..54254173b --- /dev/null +++ b/third_party/crypto/des/des.h @@ -0,0 +1,51 @@ +#ifndef DES_H +#define DES_H + +#include + +typedef uint64_t ui64; +typedef uint32_t ui32; +typedef uint8_t ui8; + +class DES +{ +public: + DES(ui64 key); + DES(ui64 *sub_key); + ui64 des(ui64 block, bool mode); + + ui64 encrypt(ui64 block); + ui64 decrypt(ui64 block); + + static ui64 encrypt(ui64 block, ui64 key); + static ui64 decrypt(ui64 block, ui64 key); + + static void set_parity(ui8 *key, int length, ui8 *out) { + for (int i = 0; i < length; i++) { + ui8 parity = key[i]; + + parity ^= parity >> 4; + parity ^= parity >> 2; + parity ^= parity >> 1; + + out[i] = (key[i] & 0xFE) | (~parity & 1); + } + } + + const ui64 *get_sub_key() const { return sub_key; } + void set_sub_key(ui64 *key); + +protected: + void keygen(ui64 key); + + ui64 ip(ui64 block); + ui64 fp(ui64 block); + + void feistel(ui32 &L, ui32 &R, ui32 F); + ui32 f(ui32 R, ui64 k); + +private: + ui64 sub_key[16]; // 48 bits each +}; + +#endif // DES_H diff --git a/third_party/crypto/des/des3.h b/third_party/crypto/des/des3.h new file mode 100644 index 000000000..4b32772ae --- /dev/null +++ b/third_party/crypto/des/des3.h @@ -0,0 +1,40 @@ +#ifndef DES3_H +#define DES3_H + +#include "des.h" + +class DES3 +{ +public: + DES3(ui64 k1, ui64 k2, ui64 k3) : des{ DES(k1), DES(k2), DES(k3) } {} + DES3(ui64* sk1, ui64* sk2, ui64* sk3) : des{ DES(sk1), DES(sk2), DES(sk3) } {} + + inline ui64 encrypt(ui64 block) + { + return des[2].encrypt(des[1].decrypt(des[0].encrypt(block))); + } + + inline ui64 decrypt(ui64 block) + { + return des[0].decrypt(des[1].encrypt(des[2].decrypt(block))); + } + + inline ui64 crypt(ui64 block, bool bEncrypt) + { + if (bEncrypt) + { + return encrypt(block); + } + else + { + return decrypt(block); + } + } + + inline DES* getDES() { return des; } + +private: + DES des[3]; +}; + +#endif // DES3_H diff --git a/third_party/crypto/des/des_data.h b/third_party/crypto/des/des_data.h new file mode 100644 index 000000000..5bda75ac9 --- /dev/null +++ b/third_party/crypto/des/des_data.h @@ -0,0 +1,121 @@ +#ifndef DES_DATA_H +#define DES_DATA_H + +#define LB32_MASK 0x00000001 +#define LB64_MASK 0x0000000000000001 +#define L64_MASK 0x00000000ffffffff + +// Initial Permutation Table [8*8] +static const char IP[] = +{ + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7 +}; + +// Inverse Initial Permutation Table [8*8] +static const char FP[] = +{ + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25 +}; + +// Expansion table [6*8] +static const char EXPANSION[] = +{ + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1 +}; + +// The S-Box tables [8*16*4] +static const char SBOX[8][64] = +{ + { + // S1 + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 + }, + { + // S2 + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 + }, + { + // S3 + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 + }, + { + // S4 + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 + }, + { + // S5 + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 + }, + { + // S6 + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 + }, + { + // S7 + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 + }, + { + // S8 + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 + } +}; + +// Post S-Box permutation [4*8] +static const char PBOX[] = +{ + 16, 7, 20, 21, + 29, 12, 28, 17, + 1, 15, 23, 26, + 5, 18, 31, 10, + 2, 8, 24, 14, + 32, 27, 3, 9, + 19, 13, 30, 6, + 22, 11, 4, 25 +}; + +#endif // DES_DATA_H diff --git a/third_party/crypto/des/des_key.h b/third_party/crypto/des/des_key.h new file mode 100644 index 000000000..ea52a5b13 --- /dev/null +++ b/third_party/crypto/des/des_key.h @@ -0,0 +1,38 @@ +#ifndef DES_KEY_H +#define DES_KEY_H + +// Permuted Choice 1 Table [7*8] +static const char PC1[] = +{ + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +// Permuted Choice 2 Table [6*8] +static const char PC2[] = +{ + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +// Iteration Shift Array +static const char ITERATION_SHIFT[] = +{ +// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 +}; + +#endif // DES_KEY_H diff --git a/third_party/crypto/des/des_lookup.h b/third_party/crypto/des/des_lookup.h new file mode 100644 index 000000000..25e78624d --- /dev/null +++ b/third_party/crypto/des/des_lookup.h @@ -0,0 +1,4 @@ +#ifndef DES_LOOKUP_H +#define DES_LOOKUP_H + +#endif // DES_LOOKUP_H diff --git a/third_party/crypto/des/descbc.h b/third_party/crypto/des/descbc.h new file mode 100644 index 000000000..30a0fa77e --- /dev/null +++ b/third_party/crypto/des/descbc.h @@ -0,0 +1,34 @@ +#ifndef DESCBC_H +#define DESCBC_H + +#include "des.h" + +class DESCBC +{ +public: + DESCBC(ui64 key, ui64 iv) : des(key), iv(iv), last_block(iv) {} + inline ui64 encrypt(ui64 block) + { + last_block = des.encrypt(block ^ last_block); + return last_block; + } + + inline ui64 decrypt(ui64 block) + { + ui64 result = des.decrypt(block) ^ last_block; + last_block = block; + return result; + } + + inline void reset() + { + last_block = iv; + } + +private: + DES des; + ui64 iv; + ui64 last_block; +}; + +#endif // DESCBC_H diff --git a/third_party/crypto/rc4.c b/third_party/crypto/rc4.c new file mode 100644 index 000000000..c98b0b143 --- /dev/null +++ b/third_party/crypto/rc4.c @@ -0,0 +1,90 @@ +/* +* rc4.c +* +* Copyright (c) 1996-2000 Whistle Communications, Inc. +* All rights reserved. +* +* Subject to the following obligations and disclaimer of warranty, use and +* redistribution of this software, in source or object code forms, with or +* without modifications are expressly permitted by Whistle Communications; +* provided, however, that: +* 1. Any and all reproductions of the source or object code must include the +* copyright notice above and the following disclaimer of warranties; and +* 2. No rights are granted, in any manner or form, to use Whistle +* Communications, Inc. trademarks, including the mark "WHISTLE +* COMMUNICATIONS" on advertising, endorsements, or otherwise except as +* such appears in the above copyright notice or in the software. +* +* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND +* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO +* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, +* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. +* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY +* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS +* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. +* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES +* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING +* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY +* OF SUCH DAMAGE. +*/ + +#include "rc4.h" + +static __inline void swap_bytes(uint8_t *a, uint8_t *b) { + uint8_t temp; + + temp = *a; + *a = *b; + *b = temp; +} + +/* +* Initialize an RC4 state buffer using the supplied key, +* which can have arbitrary length. +*/ +void rc4_init(struct rc4_state *const state, const uint8_t *key, int keylen) { + uint8_t j; + int i; + + /* Initialize state with identity permutation */ + for (i = 0; i < 256; i++) state->perm[i] = (uint8_t)i; + state->index1 = 0; + state->index2 = 0; + + /* Randomize the permutation using key data */ + for (j = i = 0; i < 256; i++) { + j += state->perm[i] + key[i % keylen]; + swap_bytes(&state->perm[i], &state->perm[j]); + } +} + +/* +* Encrypt some data using the supplied RC4 state buffer. +* The input and output buffers may be the same buffer. +* Since RC4 is a stream cypher, this function is used +* for both encryption and decryption. +*/ +void rc4_crypt(struct rc4_state *const state, const uint8_t *inbuf, + uint8_t *outbuf, int buflen) { + int i; + uint8_t j; + + for (i = 0; i < buflen; i++) { + /* Update modification indicies */ + state->index1++; + state->index2 += state->perm[state->index1]; + + /* Modify permutation */ + swap_bytes(&state->perm[state->index1], &state->perm[state->index2]); + + /* Encrypt/decrypt next byte */ + j = state->perm[state->index1] + state->perm[state->index2]; + outbuf[i] = inbuf[i] ^ state->perm[j]; + } +} diff --git a/third_party/crypto/rc4.h b/third_party/crypto/rc4.h new file mode 100644 index 000000000..6328074fb --- /dev/null +++ b/third_party/crypto/rc4.h @@ -0,0 +1,50 @@ +/* +* rc4.h +* +* Copyright (c) 1996-2000 Whistle Communications, Inc. +* All rights reserved. +* +* Subject to the following obligations and disclaimer of warranty, use and +* redistribution of this software, in source or object code forms, with or +* without modifications are expressly permitted by Whistle Communications; +* provided, however, that: +* 1. Any and all reproductions of the source or object code must include the +* copyright notice above and the following disclaimer of warranties; and +* 2. No rights are granted, in any manner or form, to use Whistle +* Communications, Inc. trademarks, including the mark "WHISTLE +* COMMUNICATIONS" on advertising, endorsements, or otherwise except as +* such appears in the above copyright notice or in the software. +* +* THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND +* TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO +* REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, +* INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. +* WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY +* REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS +* SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. +* IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES +* RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING +* WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +* PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY +* OF SUCH DAMAGE. +*/ + +#ifndef _SYS_CRYPTO_RC4_RC4_H_ +#define _SYS_CRYPTO_RC4_RC4_H_ + +struct rc4_state { + uint8_t perm[256]; + uint8_t index1; + uint8_t index2; +}; + +void rc4_init(struct rc4_state *state, const uint8_t *key, int keylen); +void rc4_crypt(struct rc4_state *state, const uint8_t *inbuf, uint8_t *outbuf, + int buflen); + +#endif diff --git a/third_party/crypto/sha256.cpp b/third_party/crypto/sha256.cpp new file mode 100644 index 000000000..f63fb2af1 --- /dev/null +++ b/third_party/crypto/sha256.cpp @@ -0,0 +1,576 @@ +// ////////////////////////////////////////////////////////// +// sha256.cpp +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// +// Altered for use in Xenia. Licensed under zlib license when acquired. + +#include "sha256.h" + +// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN +#ifndef _MSC_VER +#include +#endif + +namespace sha256 { + +/// same as reset() +SHA256::SHA256() { reset(); } + +/// restart +void SHA256::reset() { + m_numBytes = 0; + m_bufferSize = 0; + + // according to RFC 1321 + m_hash[0] = 0x6a09e667; + m_hash[1] = 0xbb67ae85; + m_hash[2] = 0x3c6ef372; + m_hash[3] = 0xa54ff53a; + m_hash[4] = 0x510e527f; + m_hash[5] = 0x9b05688c; + m_hash[6] = 0x1f83d9ab; + m_hash[7] = 0x5be0cd19; +} + +namespace { +inline uint32_t rotate(uint32_t a, uint32_t c) { + return (a >> c) | (a << (32 - c)); +} + +inline uint32_t swap(uint32_t x) { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap32(x); +#endif +#ifdef MSC_VER + return _byteswap_ulong(x); +#endif + + return (x >> 24) | ((x >> 8) & 0x0000FF00) | ((x << 8) & 0x00FF0000) | + (x << 24); +} + +// mix functions for processBlock() +inline uint32_t f1(uint32_t e, uint32_t f, uint32_t g) { + uint32_t term1 = rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25); + uint32_t term2 = (e & f) ^ (~e & g); //(g ^ (e & (f ^ g))) + return term1 + term2; +} + +inline uint32_t f2(uint32_t a, uint32_t b, uint32_t c) { + uint32_t term1 = rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22); + uint32_t term2 = ((a | b) & c) | (a & b); //(a & (b ^ c)) ^ (b & c); + return term1 + term2; +} +} + +/// process 64 bytes +void SHA256::processBlock(const void* data) { + // get last hash + uint32_t a = m_hash[0]; + uint32_t b = m_hash[1]; + uint32_t c = m_hash[2]; + uint32_t d = m_hash[3]; + uint32_t e = m_hash[4]; + uint32_t f = m_hash[5]; + uint32_t g = m_hash[6]; + uint32_t h = m_hash[7]; + + // data represented as 16x 32-bit words + const uint32_t* input = (uint32_t*)data; + // convert to big endian + uint32_t words[64]; + int i; + for (i = 0; i < 16; i++) +#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && \ + (__BYTE_ORDER == __BIG_ENDIAN) + words[i] = input[i]; +#else + words[i] = swap(input[i]); +#endif + + uint32_t x, y; // temporaries + + // first round + x = h + f1(e, f, g) + 0x428a2f98 + words[0]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0x71374491 + words[1]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0xb5c0fbcf + words[2]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0xe9b5dba5 + words[3]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x3956c25b + words[4]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0x59f111f1 + words[5]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x923f82a4 + words[6]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0xab1c5ed5 + words[7]; + y = f2(b, c, d); + e += x; + a = x + y; + + // secound round + x = h + f1(e, f, g) + 0xd807aa98 + words[8]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0x12835b01 + words[9]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0x243185be + words[10]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0x550c7dc3 + words[11]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x72be5d74 + words[12]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0x80deb1fe + words[13]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x9bdc06a7 + words[14]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0xc19bf174 + words[15]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 24 words + for (; i < 24; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // third round + x = h + f1(e, f, g) + 0xe49b69c1 + words[16]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0xefbe4786 + words[17]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0x0fc19dc6 + words[18]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0x240ca1cc + words[19]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x2de92c6f + words[20]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0x4a7484aa + words[21]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x5cb0a9dc + words[22]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0x76f988da + words[23]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 32 words + for (; i < 32; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // fourth round + x = h + f1(e, f, g) + 0x983e5152 + words[24]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0xa831c66d + words[25]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0xb00327c8 + words[26]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0xbf597fc7 + words[27]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0xc6e00bf3 + words[28]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0xd5a79147 + words[29]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x06ca6351 + words[30]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0x14292967 + words[31]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 40 words + for (; i < 40; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // fifth round + x = h + f1(e, f, g) + 0x27b70a85 + words[32]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0x2e1b2138 + words[33]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0x4d2c6dfc + words[34]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0x53380d13 + words[35]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x650a7354 + words[36]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0x766a0abb + words[37]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x81c2c92e + words[38]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0x92722c85 + words[39]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 48 words + for (; i < 48; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // sixth round + x = h + f1(e, f, g) + 0xa2bfe8a1 + words[40]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0xa81a664b + words[41]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0xc24b8b70 + words[42]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0xc76c51a3 + words[43]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0xd192e819 + words[44]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0xd6990624 + words[45]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0xf40e3585 + words[46]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0x106aa070 + words[47]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 56 words + for (; i < 56; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // seventh round + x = h + f1(e, f, g) + 0x19a4c116 + words[48]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0x1e376c08 + words[49]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0x2748774c + words[50]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0x34b0bcb5 + words[51]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x391c0cb3 + words[52]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0x4ed8aa4a + words[53]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0x5b9cca4f + words[54]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0x682e6ff3 + words[55]; + y = f2(b, c, d); + e += x; + a = x + y; + + // extend to 64 words + for (; i < 64; i++) + words[i] = words[i - 16] + + (rotate(words[i - 15], 7) ^ rotate(words[i - 15], 18) ^ + (words[i - 15] >> 3)) + + words[i - 7] + (rotate(words[i - 2], 17) ^ + rotate(words[i - 2], 19) ^ (words[i - 2] >> 10)); + + // eigth round + x = h + f1(e, f, g) + 0x748f82ee + words[56]; + y = f2(a, b, c); + d += x; + h = x + y; + x = g + f1(d, e, f) + 0x78a5636f + words[57]; + y = f2(h, a, b); + c += x; + g = x + y; + x = f + f1(c, d, e) + 0x84c87814 + words[58]; + y = f2(g, h, a); + b += x; + f = x + y; + x = e + f1(b, c, d) + 0x8cc70208 + words[59]; + y = f2(f, g, h); + a += x; + e = x + y; + x = d + f1(a, b, c) + 0x90befffa + words[60]; + y = f2(e, f, g); + h += x; + d = x + y; + x = c + f1(h, a, b) + 0xa4506ceb + words[61]; + y = f2(d, e, f); + g += x; + c = x + y; + x = b + f1(g, h, a) + 0xbef9a3f7 + words[62]; + y = f2(c, d, e); + f += x; + b = x + y; + x = a + f1(f, g, h) + 0xc67178f2 + words[63]; + y = f2(b, c, d); + e += x; + a = x + y; + + // update hash + m_hash[0] += a; + m_hash[1] += b; + m_hash[2] += c; + m_hash[3] += d; + m_hash[4] += e; + m_hash[5] += f; + m_hash[6] += g; + m_hash[7] += h; +} + +/// add arbitrary number of bytes +void SHA256::add(const void* data, size_t numBytes) { + const uint8_t* current = (const uint8_t*)data; + + if (m_bufferSize > 0) { + while (numBytes > 0 && m_bufferSize < BlockSize) { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } + } + + // full buffer + if (m_bufferSize == BlockSize) { + processBlock(m_buffer); + m_numBytes += BlockSize; + m_bufferSize = 0; + } + + // no more data ? + if (numBytes == 0) return; + + // process full blocks + while (numBytes >= BlockSize) { + processBlock(current); + current += BlockSize; + m_numBytes += BlockSize; + numBytes -= BlockSize; + } + + // keep remaining bytes in buffer + while (numBytes > 0) { + m_buffer[m_bufferSize++] = *current++; + numBytes--; + } +} + +/// process final block, less than 64 bytes +void SHA256::processBuffer() { + // the input bytes are considered as bits strings, where the first bit is the + // most significant bit of the byte + + // - append "1" bit to message + // - append "0" bits until message length in bit mod 512 is 448 + // - append length as 64 bit integer + + // number of bits + size_t paddedLength = m_bufferSize * 8; + + // plus one bit set to 1 (always appended) + paddedLength++; + + // number of bits must be (numBits % 512) = 448 + size_t lower11Bits = paddedLength & 511; + if (lower11Bits <= 448) + paddedLength += 448 - lower11Bits; + else + paddedLength += 512 + 448 - lower11Bits; + // convert from bits to bytes + paddedLength /= 8; + + // only needed if additional data flows over into a second block + unsigned char extra[BlockSize]; + + // append a "1" bit, 128 => binary 10000000 + if (m_bufferSize < BlockSize) + m_buffer[m_bufferSize] = 128; + else + extra[0] = 128; + + size_t i; + for (i = m_bufferSize + 1; i < BlockSize; i++) m_buffer[i] = 0; + for (; i < paddedLength; i++) extra[i - BlockSize] = 0; + + // add message length in bits as 64 bit number + uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); + // find right position + unsigned char* addLength; + if (paddedLength < BlockSize) + addLength = m_buffer + paddedLength; + else + addLength = extra + paddedLength - BlockSize; + + // must be big endian + *addLength++ = (unsigned char)((msgBits >> 56) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 48) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 40) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 32) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 24) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 16) & 0xFF); + *addLength++ = (unsigned char)((msgBits >> 8) & 0xFF); + *addLength = (unsigned char)(msgBits & 0xFF); + + // process blocks + processBlock(m_buffer); + // flowed over into a second block ? + if (paddedLength > BlockSize) processBlock(extra); +} + +/// return latest hash as 64 hex characters +std::string SHA256::getHash() { + // compute hash (as raw bytes) + unsigned char rawHash[HashBytes]; + getHash(rawHash); + + // convert to hex string + std::string result; + result.reserve(2 * HashBytes); + for (int i = 0; i < HashBytes; i++) { + static const char dec2hex[16 + 1] = "0123456789abcdef"; + result += dec2hex[(rawHash[i] >> 4) & 15]; + result += dec2hex[rawHash[i] & 15]; + } + + return result; +} + +/// return latest hash as bytes +void SHA256::getHash(unsigned char buffer[SHA256::HashBytes]) { + // save old hash if buffer is partially filled + uint32_t oldHash[HashValues]; + for (int i = 0; i < HashValues; i++) oldHash[i] = m_hash[i]; + + // process remaining bytes + processBuffer(); + + unsigned char* current = buffer; + for (int i = 0; i < HashValues; i++) { + *current++ = (m_hash[i] >> 24) & 0xFF; + *current++ = (m_hash[i] >> 16) & 0xFF; + *current++ = (m_hash[i] >> 8) & 0xFF; + *current++ = m_hash[i] & 0xFF; + + // restore old hash + m_hash[i] = oldHash[i]; + } +} + +/// compute SHA256 of a memory block +std::string SHA256::operator()(const void* data, size_t numBytes) { + reset(); + add(data, numBytes); + return getHash(); +} + +/// compute SHA256 of a string, excluding final zero +std::string SHA256::operator()(const std::string& text) { + reset(); + add(text.c_str(), text.size()); + return getHash(); +} + +} \ No newline at end of file diff --git a/third_party/crypto/sha256.h b/third_party/crypto/sha256.h new file mode 100644 index 000000000..e8aeae2f9 --- /dev/null +++ b/third_party/crypto/sha256.h @@ -0,0 +1,79 @@ +// ////////////////////////////////////////////////////////// +// sha256.h +// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. +// see http://create.stephan-brumme.com/disclaimer.html +// +// Altered for use in Xenia. Licensed under zlib license when acquired. + +#pragma once + +#include +#include + +namespace sha256 { + +/// compute SHA256 hash +/** Usage: + SHA256 sha256; + std::string myHash = sha256("Hello World"); // std::string + std::string myHash2 = sha256("How are you", 11); // arbitrary data, 11 bytes + + // or in a streaming fashion: + + SHA256 sha256; + while (more data available) + sha256.add(pointer to fresh data, number of new bytes); + std::string myHash3 = sha256.getHash(); + */ +class SHA256 { + public: + /// split into 64 byte blocks (=> 512 bits), hash is 32 bytes long + enum { BlockSize = 512 / 8, HashBytes = 32 }; + + /// same as reset() + SHA256(); + + /// compute SHA256 of a memory block + std::string operator()(const void* data, size_t numBytes); + /// compute SHA256 of a string, excluding final zero + std::string operator()(const std::string& text); + + /// add arbitrary number of bytes + void add(const void* data, size_t numBytes); + + /// return latest hash as 64 hex characters + std::string getHash(); + /// return latest hash as bytes + void getHash(unsigned char buffer[HashBytes]); + + uint8_t* getBuffer() { return m_buffer; } + uint32_t* getHashValues() { return m_hash; } + + size_t getTotalSize() const { return m_numBytes + m_bufferSize; } + void setTotalSize(size_t size) { + m_bufferSize = size & (BlockSize - 1); + m_numBytes = size & ~(BlockSize - 1); + } + + /// restart + void reset(); + + private: + /// process 64 bytes + void processBlock(const void* data); + /// process everything left in the internal buffer + void processBuffer(); + + /// size of processed data in bytes + uint64_t m_numBytes; + /// valid bytes in m_buffer + size_t m_bufferSize; + /// bytes not processed yet + uint8_t m_buffer[BlockSize]; + + enum { HashValues = HashBytes / 4 }; + /// hash, stored as integers + uint32_t m_hash[HashValues]; +}; + +}; // namespace sha256 \ No newline at end of file