Skip to content

Commit

Permalink
bum baskets
Browse files Browse the repository at this point in the history
  • Loading branch information
CCIGAMES committed Mar 2, 2024
1 parent cbc9295 commit 1583308
Show file tree
Hide file tree
Showing 2 changed files with 361 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<uint8>& 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);
}
Original file line number Diff line number Diff line change
@@ -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 <rmxbase.h>


class Crypto
{
public:
static bool decodeBase64(std::string_view encodedString, std::vector<uint8>& 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
};

0 comments on commit 1583308

Please sign in to comment.