From 15833085bcb978cf9e9d73ecfd1ddebf5f707667 Mon Sep 17 00:00:00 2001 From: "Crunch (Chaz9)" Date: Sat, 2 Mar 2024 17:29:30 +0000 Subject: [PATCH] bum baskets --- .../network/internal/CryptoFunctions.cpp | 340 ++++++++++++++++++ .../network/internal/CryptoFunctions.h | 21 ++ 2 files changed, 361 insertions(+) create mode 100644 sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.cpp create mode 100644 sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.h diff --git a/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.cpp b/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.cpp new file mode 100644 index 00000000..c165e962 --- /dev/null +++ b/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.cpp @@ -0,0 +1,340 @@ +/* +* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. +* Copyright (C) 2017-2024 by Eukaryot +* +* Published under the GNU GPLv3 open source software license, see license.txt +* or https://www.gnu.org/licenses/gpl-3.0.en.html +*/ + +#include "oxygen_netcore/pch.h" +#include "oxygen_netcore/network/internal/CryptoFunctions.h" + + +namespace sha1 +{ + // Based on https://github.com/vog/sha1/blob/master/sha1.hpp (public domain) + class SHA1 + { + public: + SHA1(); + void update(const std::string& s); + void update(std::istream &is); + void finalize(uint32* output); + + private: + static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */ + static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ + static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4; + + uint32 digest[DIGEST_INTS]; + std::string buffer; + uint64 transforms = 0; + + void reset(); + void transform(uint32 block[BLOCK_BYTES]); + + static void buffer_to_block(const std::string& buffer, uint32 block[BLOCK_BYTES]); + static void read(std::istream &is, std::string& s, int max); + }; + + + /* Help macros */ + #define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits)))) + #define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1)) + + /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ + #define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + #define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + #define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + #define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + #define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); + + SHA1::SHA1() + { + reset(); + } + + void SHA1::update(const std::string& s) + { + std::istringstream is(s); + update(is); + } + + void SHA1::update(std::istream &is) + { + std::string rest_of_buffer; + read(is, rest_of_buffer, (int)BLOCK_BYTES - (int)buffer.size()); + buffer += rest_of_buffer; + + while (is) + { + uint32 block[BLOCK_INTS]; + buffer_to_block(buffer, block); + transform(block); + read(is, buffer, BLOCK_BYTES); + } + } + + void SHA1::finalize(uint32* output) + { + /* Total number of hashed bits */ + uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; + + /* Padding */ + buffer += (char)0x80; + unsigned int orig_size = (unsigned int)buffer.size(); + while (buffer.size() < BLOCK_BYTES) + { + buffer += (char)0x00; + } + + uint32 block[BLOCK_INTS]; + buffer_to_block(buffer, block); + + if (orig_size > BLOCK_BYTES - 8) + { + transform(block); + for (unsigned int i = 0; i < BLOCK_INTS - 2; i++) + { + block[i] = 0; + } + } + + /* Append total_bits, split this uint64 into two uint32 */ + block[BLOCK_INTS - 1] = (uint32)total_bits; + block[BLOCK_INTS - 2] = (uint32)(total_bits >> 32); + transform(block); + + for (uint32 k = 0; k < DIGEST_INTS; ++k) + output[k] = digest[k]; + } + + void SHA1::reset() + { + /* SHA1 initialization constants */ + digest[0] = 0x67452301; + digest[1] = 0xefcdab89; + digest[2] = 0x98badcfe; + digest[3] = 0x10325476; + digest[4] = 0xc3d2e1f0; + + /* Reset counters */ + transforms = 0; + buffer = ""; + } + + void SHA1::transform(uint32 block[BLOCK_BYTES]) + { + /* Copy digest[] to working vars */ + uint32 a = digest[0]; + uint32 b = digest[1]; + uint32 c = digest[2]; + uint32 d = digest[3]; + uint32 e = digest[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + SHA1_R0(a,b,c,d,e, 0); + SHA1_R0(e,a,b,c,d, 1); + SHA1_R0(d,e,a,b,c, 2); + SHA1_R0(c,d,e,a,b, 3); + SHA1_R0(b,c,d,e,a, 4); + SHA1_R0(a,b,c,d,e, 5); + SHA1_R0(e,a,b,c,d, 6); + SHA1_R0(d,e,a,b,c, 7); + SHA1_R0(c,d,e,a,b, 8); + SHA1_R0(b,c,d,e,a, 9); + SHA1_R0(a,b,c,d,e,10); + SHA1_R0(e,a,b,c,d,11); + SHA1_R0(d,e,a,b,c,12); + SHA1_R0(c,d,e,a,b,13); + SHA1_R0(b,c,d,e,a,14); + SHA1_R0(a,b,c,d,e,15); + SHA1_R1(e,a,b,c,d,16); + SHA1_R1(d,e,a,b,c,17); + SHA1_R1(c,d,e,a,b,18); + SHA1_R1(b,c,d,e,a,19); + SHA1_R2(a,b,c,d,e,20); + SHA1_R2(e,a,b,c,d,21); + SHA1_R2(d,e,a,b,c,22); + SHA1_R2(c,d,e,a,b,23); + SHA1_R2(b,c,d,e,a,24); + SHA1_R2(a,b,c,d,e,25); + SHA1_R2(e,a,b,c,d,26); + SHA1_R2(d,e,a,b,c,27); + SHA1_R2(c,d,e,a,b,28); + SHA1_R2(b,c,d,e,a,29); + SHA1_R2(a,b,c,d,e,30); + SHA1_R2(e,a,b,c,d,31); + SHA1_R2(d,e,a,b,c,32); + SHA1_R2(c,d,e,a,b,33); + SHA1_R2(b,c,d,e,a,34); + SHA1_R2(a,b,c,d,e,35); + SHA1_R2(e,a,b,c,d,36); + SHA1_R2(d,e,a,b,c,37); + SHA1_R2(c,d,e,a,b,38); + SHA1_R2(b,c,d,e,a,39); + SHA1_R3(a,b,c,d,e,40); + SHA1_R3(e,a,b,c,d,41); + SHA1_R3(d,e,a,b,c,42); + SHA1_R3(c,d,e,a,b,43); + SHA1_R3(b,c,d,e,a,44); + SHA1_R3(a,b,c,d,e,45); + SHA1_R3(e,a,b,c,d,46); + SHA1_R3(d,e,a,b,c,47); + SHA1_R3(c,d,e,a,b,48); + SHA1_R3(b,c,d,e,a,49); + SHA1_R3(a,b,c,d,e,50); + SHA1_R3(e,a,b,c,d,51); + SHA1_R3(d,e,a,b,c,52); + SHA1_R3(c,d,e,a,b,53); + SHA1_R3(b,c,d,e,a,54); + SHA1_R3(a,b,c,d,e,55); + SHA1_R3(e,a,b,c,d,56); + SHA1_R3(d,e,a,b,c,57); + SHA1_R3(c,d,e,a,b,58); + SHA1_R3(b,c,d,e,a,59); + SHA1_R4(a,b,c,d,e,60); + SHA1_R4(e,a,b,c,d,61); + SHA1_R4(d,e,a,b,c,62); + SHA1_R4(c,d,e,a,b,63); + SHA1_R4(b,c,d,e,a,64); + SHA1_R4(a,b,c,d,e,65); + SHA1_R4(e,a,b,c,d,66); + SHA1_R4(d,e,a,b,c,67); + SHA1_R4(c,d,e,a,b,68); + SHA1_R4(b,c,d,e,a,69); + SHA1_R4(a,b,c,d,e,70); + SHA1_R4(e,a,b,c,d,71); + SHA1_R4(d,e,a,b,c,72); + SHA1_R4(c,d,e,a,b,73); + SHA1_R4(b,c,d,e,a,74); + SHA1_R4(a,b,c,d,e,75); + SHA1_R4(e,a,b,c,d,76); + SHA1_R4(d,e,a,b,c,77); + SHA1_R4(c,d,e,a,b,78); + SHA1_R4(b,c,d,e,a,79); + + /* Add the working vars back into digest[] */ + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; + + /* Count the number of transformations */ + ++transforms; + } + + void SHA1::buffer_to_block(const std::string& buffer, uint32 block[BLOCK_BYTES]) + { + /* Convert the std::string (byte buffer) to a uint32 array (MSB) */ + for (unsigned int i = 0; i < BLOCK_INTS; i++) + { + block[i] = (buffer[4*i+3] & 0xff) + | (buffer[4*i+2] & 0xff) << 8 + | (buffer[4*i+1] & 0xff) << 16 + | (buffer[4*i+0] & 0xff) << 24; + } + } + + void SHA1::read(std::istream &is, std::string& s, int max) + { + char sbuf[BLOCK_BYTES]; + is.read(sbuf, max); + s.assign(sbuf, (size_t)is.gcount()); + } +} + + +namespace Base64 +{ + static const constexpr char ENCODER_LOOKUP[64] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + static uint8 DECODER_LOOKUP[0x100] = { 0 }; +} + + +bool Crypto::decodeBase64(std::string_view encodedString, std::vector& outData) +{ + if (Base64::DECODER_LOOKUP[0] == 0) + { + // Build reverse lookup + for (int k = 0; k < 256; ++k) + Base64::DECODER_LOOKUP[k] = 0xff; + for (int k = 0; k < 64; ++k) + Base64::DECODER_LOOKUP[Base64::ENCODER_LOOKUP[k]] = k; + Base64::DECODER_LOOKUP[(size_t)'='] = 0; + } + + outData.clear(); + outData.reserve(encodedString.length() / 4 * 3); + for (size_t k = 0; k < encodedString.length() - 3; k += 4) + { + const uint8 bits0 = Base64::DECODER_LOOKUP[encodedString[k]]; + const uint8 bits1 = Base64::DECODER_LOOKUP[encodedString[k+1]]; + const uint8 bits2 = Base64::DECODER_LOOKUP[encodedString[k+2]]; + const uint8 bits3 = Base64::DECODER_LOOKUP[encodedString[k+3]]; + if (bits0 == 0xff || bits1 == 0xff || bits2 == 0xff || bits3 == 0xff) + return false; + + // TODO: Leave out bytes added just for padding? + outData.push_back((bits0 << 2) | (bits1 >> 4)); + outData.push_back((bits1 << 4) | (bits2 >> 2)); + outData.push_back((bits2 << 6) | bits3); + } + return true; +} + +std::string Crypto::encodeBase64(const uint8* data, size_t length) +{ + const size_t numOutputBytesMinimal = (length * 4 + 2) / 3; + const size_t numOutputBytesTotal = (length + 2) / 3 * 4; + std::string output; + output.reserve(numOutputBytesTotal); + + size_t offset = 0; + while (offset < length) + { + // Build 4 values of 6-bits from the next 3 bytes + uint8 buffer[3]; + const uint8* bytes; + if (offset + 3 < length) + { + bytes = &data[offset]; + offset += 3; + } + else + { + for (int k = 0; k < 3; ++k) + buffer[k] = (offset + k < length) ? data[offset + k] : 0; + bytes = buffer; + offset = length; + } + + uint8 values[4]; + values[0] = ((bytes[0] >> 2) & 0x3f); + values[1] = ((bytes[0] << 4) & 0x30) | ((bytes[1] >> 4) & 0x0f); + values[2] = ((bytes[1] << 2) & 0x3c) | ((bytes[2] >> 6) & 0x03); + values[3] = (bytes[2] & 0x3f); + + for (int k = 0; k < 4; ++k) + output.push_back(Base64::ENCODER_LOOKUP[values[k]]); + } + for (size_t k = numOutputBytesMinimal; k < numOutputBytesTotal; ++k) + output[k] = '='; + return output; +} + +void Crypto::buildSHA1(const std::string& string, uint32* output) +{ + sha1::SHA1 checksum; + checksum.update(string); + checksum.finalize(output); +} diff --git a/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.h b/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.h new file mode 100644 index 00000000..8dfdad96 --- /dev/null +++ b/sonic3air-main/Oxygen/oxygenengine/source/oxygen_netcore/network/internal/CryptoFunctions.h @@ -0,0 +1,21 @@ +/* +* Part of the Oxygen Engine / Sonic 3 A.I.R. software distribution. +* Copyright (C) 2017-2024 by Eukaryot +* +* Published under the GNU GPLv3 open source software license, see license.txt +* or https://www.gnu.org/licenses/gpl-3.0.en.html +*/ + +#pragma once + +#include + + +class Crypto +{ +public: + static bool decodeBase64(std::string_view encodedString, std::vector& outData); + static std::string encodeBase64(const uint8* data, size_t length); + + static void buildSHA1(const std::string& string, uint32* output); // Output is supposed to be 5 uint32 values +};