aboutsummaryrefslogtreecommitdiff
path: root/src/sha256.cc
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-07-15 23:37:52 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-07-15 23:37:52 -0300
commit5463c34177066b9860c9d77c6d7d59c265052399 (patch)
tree828956ca1a0f04673d55e00554f909dd66ac4c36 /src/sha256.cc
parent8bc672f7111287e6e0b66e5897e80795652dc1c7 (diff)
downloadquerymanager-5463c34177066b9860c9d77c6d7d59c265052399.tar.gz
querymanager-5463c34177066b9860c9d77c6d7d59c265052399.zip
finish game queries
Diffstat (limited to 'src/sha256.cc')
-rw-r--r--src/sha256.cc247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/sha256.cc b/src/sha256.cc
new file mode 100644
index 0000000..1070c6b
--- /dev/null
+++ b/src/sha256.cc
@@ -0,0 +1,247 @@
+#include "querymanager.hh"
+
+static const uint32 SHA256IV[8] = {
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
+};
+
+static const uint32 SHA256K[64] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+static uint32 RotR32(uint32 Value, int N){
+ ASSERT(N >= 0 && N < 32);
+ return (Value >> N) | (Value << (32 - N));
+}
+
+static void SHA256Compress(uint32 *H, const uint8 *Block){
+ uint32 W[64];
+
+ for(int i = 0; i < 16; i += 1){
+ W[i] = BufferRead32BE(&Block[i * 4]);
+ }
+
+ for(int i = 16; i < 64; i += 1){
+ uint32 S0 = RotR32(W[i - 15], 7) ^ RotR32(W[i - 15], 18) ^ (W[i - 15] >> 3);
+ uint32 S1 = RotR32(W[i - 2], 17) ^ RotR32(W[i - 2], 19) ^ (W[i - 2] >> 10);
+ W[i] = W[i - 16] + S0 + W[i - 7] + S1;
+ }
+
+ uint32 Aux[8];
+ memcpy(Aux, H, sizeof(uint32) * 8);
+ for(int i = 0; i < 64; i += 1){
+ uint32 S1 = RotR32(Aux[4], 6) ^ RotR32(Aux[4], 11) ^ RotR32(Aux[4], 25);
+ uint32 Ch = (Aux[4] & Aux[5]) ^ (~Aux[4] & Aux[6]);
+ uint32 T1 = Aux[7] + S1 + Ch + SHA256K[i] + W[i];
+
+ uint32 S0 = RotR32(Aux[0], 2) ^ RotR32(Aux[0], 13) ^ RotR32(Aux[0], 22);
+ uint32 Maj = (Aux[0] & Aux[1]) ^ (Aux[0] & Aux[2]) ^ (Aux[1] & Aux[2]);
+ uint32 T2 = S0 + Maj;
+
+ Aux[7] = Aux[6];
+ Aux[6] = Aux[5];
+ Aux[5] = Aux[4];
+ Aux[4] = Aux[3] + T1;
+ Aux[3] = Aux[2];
+ Aux[2] = Aux[1];
+ Aux[1] = Aux[0];
+ Aux[0] = T1 + T2;
+ }
+
+ H[0] += Aux[0];
+ H[1] += Aux[1];
+ H[2] += Aux[2];
+ H[3] += Aux[3];
+ H[4] += Aux[4];
+ H[5] += Aux[5];
+ H[6] += Aux[6];
+ H[7] += Aux[7];
+}
+
+void SHA256(const uint8 *Input, int InputBytes, uint8 *Digest){
+ ASSERT(Input != NULL && InputBytes >= 0 && Digest != NULL);
+ uint32 H[8];
+ memcpy(H, SHA256IV, sizeof(uint32) * 8);
+
+ const uint8 *InputPtr = Input;
+ int InputRem = InputBytes;
+ while(InputRem >= 64){
+ SHA256Compress(H, InputPtr);
+ InputPtr += 64;
+ InputRem -= 64;
+ }
+
+ ASSERT(InputRem < 64);
+ uint8 Block[64] = {};
+ memcpy(Block, InputPtr, InputRem);
+ BufferWrite8(&Block[InputRem], 0x80);
+ if(InputRem > 55){
+ SHA256Compress(H, Block);
+ memset(Block, 0, sizeof(Block));
+ }
+ BufferWrite64BE(&Block[56], ((uint64)InputBytes * 8));
+ SHA256Compress(H, Block);
+
+ BufferWrite32BE(&Digest[ 0], H[0]);
+ BufferWrite32BE(&Digest[ 4], H[1]);
+ BufferWrite32BE(&Digest[ 8], H[2]);
+ BufferWrite32BE(&Digest[12], H[3]);
+ BufferWrite32BE(&Digest[16], H[4]);
+ BufferWrite32BE(&Digest[20], H[5]);
+ BufferWrite32BE(&Digest[24], H[6]);
+ BufferWrite32BE(&Digest[28], H[7]);
+}
+
+bool TestPassword(const uint8 *Auth, int AuthSize, const char *Password){
+ if(AuthSize != 64){
+ LOG_ERR("Expected 64 bytes of authentication data (got %d)", AuthSize);
+ return false;
+ }
+
+ // NOTE(fusion): Constant time comparison to check whether the authentication
+ // data is set. I'm considering all zeros to be NOT set.
+ bool IsSet = false;
+ for(int i = 0; i < AuthSize; i += 1){
+ if(Auth[i] != 0){
+ IsSet = true;
+ }
+ }
+
+ if(!IsSet){
+ LOG_ERR("Authentication data not set");
+ return false;
+ }
+
+ const uint8 *Hash = &Auth[ 0];
+ const uint8 *Salt = &Auth[32];
+
+ // TODO(fusion): It's probably not the best way to mix the salt but should
+ // be better than using plaintext or non-salted hashing schemes.
+ uint8 Digest[32];
+ SHA256((const uint8*)Password, (int)strlen(Password), Digest);
+ for(int i = 0; i < 32; i += 1){
+ Digest[i] ^= Salt[i];
+ }
+ SHA256(Digest, 32, Digest);
+
+ // NOTE(fusion): Constant time comparison.
+ uint8 Result = 0;
+ for(int i = 0; i < 32; i += 1){
+ Result |= Digest[i] ^ Hash[i];
+ }
+ return Result == 0;;
+}
+
+// CheckSHA256
+//==============================================================================
+static int HexDigit(int Ch){
+ if(Ch >= '0' && Ch <= '9'){
+ return (Ch - '0');
+ }else if(Ch >= 'A' && Ch <= 'F'){
+ return (Ch - 'A') + 10;
+ }else if(Ch >= 'a' && Ch <= 'f'){
+ return (Ch - 'a') + 10;
+ }else{
+ return -1;
+ }
+}
+
+static int ParseHexString(uint8 *Buffer, int BufferSize, const char *String){
+ int StringLen = (int)strlen(String);
+ if(StringLen % 2 != 0){
+ LOG_ERR("Expected even number of characters");
+ return -1;
+ }
+
+ int NumBytes = (StringLen / 2);
+ if(NumBytes > BufferSize){
+ LOG_ERR("Supplied buffer is too small (Size: %d, Required: %d)",
+ BufferSize, NumBytes);
+ return -1;
+ }
+
+ for(int i = 0; i < NumBytes; i += 1){
+ int Digit0 = HexDigit(String[i * 2 + 0]);
+ int Digit1 = HexDigit(String[i * 2 + 1]);
+ if(Digit0 == -1 || Digit1 == -1){
+ LOG_ERR("Invalid hex digit at offset %d", i * 2);
+ return -1;
+ }
+
+ Buffer[i] = ((uint8)Digit0 << 4) | (uint8)Digit1;
+ }
+
+ return NumBytes;
+}
+
+bool CheckSHA256(void){
+ // NOTE(fusion): We're using only a few NIST test vectors. This is to make
+ // sure there are no blatant implementation errors but we'd ideally run it
+ // against all of them to be sure.
+ struct{
+ const char *Input;
+ const char *Expected;
+ } Tests[] = {
+ {
+ "",
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ },
+ {
+ "5738c929c4f4ccb6",
+ "963bb88f27f512777aab6c8b1a02c70ec0ad651d428f870036e1917120fb48bf",
+ },
+ {
+ "1b503fb9a73b16ada3fcf1042623ae7610",
+ "d5c30315f72ed05fe519a1bf75ab5fd0ffec5ac1acb0daf66b6b769598594509",
+ },
+ {
+ "09fc1accc230a205e4a208e64a8f204291f581a12756392da4b8c0cf5ef02b95",
+ "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4",
+ },
+ {
+ "03b264be51e4b941864f9b70b4c958f5355aac294b4b87cb037f11f85f07eb57"
+ "b3f0b89550",
+ "d1f8bd684001ac5a4b67bbf79f87de524d2da99ac014dec3e4187728f4557471",
+ },
+ {
+ "d1be3f13febafefc14414d9fb7f693db16dc1ae270c5b647d80da8583587c1ad"
+ "8cb8cb01824324411ca5ace3ca22e179a4ff4986f3f21190f3d7f3",
+ "02804978eba6e1de65afdbc6a6091ed6b1ecee51e8bff40646a251de6678b7ef",
+ }
+ };
+
+ uint8 Input[64];
+ uint8 Expected[32];
+ uint8 Digest[32];
+ for(int i = 0; i < NARRAY(Tests); i += 1){
+ int InputBytes = ParseHexString(Input, sizeof(Input), Tests[i].Input);
+ int ExpectedBytes = ParseHexString(Expected, sizeof(Expected), Tests[i].Expected);
+ if(InputBytes == -1 || ExpectedBytes != sizeof(Expected)){
+ LOG_ERR("Invalid test vector %d", i);
+ return false;
+ }
+
+ SHA256(Input, InputBytes, Digest);
+ if(memcmp(Expected, Digest, 32) != 0){
+ LOG_ERR("Test vector %d failed", i);
+ return false;
+ }
+ }
+
+ return true;
+}