Files
MeshCore/test/mocks/SHA256.h

108 lines
4.3 KiB
C++

#pragma once
#include <stdint.h>
#include <stddef.h>
#include <string.h>
// Real SHA-256 for native/host tests. Mirrors the rweather/Crypto streaming API used by
// src/Utils.cpp (update / finalize-with-truncation, plus resetHMAC / finalizeHMAC), so that
// Utils::sha256(...) produces correct digests on the host and OTA merkle tests are meaningful.
// (On-device the real rweather <SHA256.h> is used instead of this mock.)
class SHA256 {
uint32_t h[8];
uint8_t buf[64];
uint32_t buf_len;
uint64_t total_len;
uint8_t hmac_key[64];
static uint32_t ror(uint32_t x, uint32_t n) { return (x >> n) | (x << (32 - n)); }
void process(const uint8_t* p) {
static const uint32_t K[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};
uint32_t w[64];
for (int i = 0; i < 16; i++)
w[i] = ((uint32_t)p[i*4] << 24) | ((uint32_t)p[i*4+1] << 16) | ((uint32_t)p[i*4+2] << 8) | p[i*4+3];
for (int i = 16; i < 64; i++) {
uint32_t s0 = ror(w[i-15],7) ^ ror(w[i-15],18) ^ (w[i-15] >> 3);
uint32_t s1 = ror(w[i-2],17) ^ ror(w[i-2],19) ^ (w[i-2] >> 10);
w[i] = w[i-16] + s0 + w[i-7] + s1;
}
uint32_t a=h[0],b=h[1],c=h[2],d=h[3],e=h[4],f=h[5],g=h[6],hh=h[7];
for (int i = 0; i < 64; i++) {
uint32_t S1 = ror(e,6) ^ ror(e,11) ^ ror(e,25);
uint32_t ch = (e & f) ^ ((~e) & g);
uint32_t t1 = hh + S1 + ch + K[i] + w[i];
uint32_t S0 = ror(a,2) ^ ror(a,13) ^ ror(a,22);
uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
uint32_t t2 = S0 + maj;
hh=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2;
}
h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; h[4]+=e; h[5]+=f; h[6]+=g; h[7]+=hh;
}
public:
SHA256() { reset(); }
void reset() {
h[0]=0x6a09e667; h[1]=0xbb67ae85; h[2]=0x3c6ef372; h[3]=0xa54ff53a;
h[4]=0x510e527f; h[5]=0x9b05688c; h[6]=0x1f83d9ab; h[7]=0x5be0cd19;
buf_len = 0; total_len = 0;
}
void update(const uint8_t* data, size_t n) {
total_len += n;
while (n) {
size_t take = 64 - buf_len; if (take > n) take = n;
memcpy(buf + buf_len, data, take); buf_len += (uint32_t)take; data += take; n -= take;
if (buf_len == 64) { process(buf); buf_len = 0; }
}
}
void update(const void* data, size_t n) {
update(static_cast<const uint8_t*>(data), n);
}
void finalize(uint8_t* out, size_t out_len) {
uint64_t bits = total_len * 8;
buf[buf_len++] = 0x80;
if (buf_len > 56) { while (buf_len < 64) buf[buf_len++] = 0; process(buf); buf_len = 0; }
while (buf_len < 56) buf[buf_len++] = 0;
for (int i = 0; i < 8; i++) buf[56 + i] = (uint8_t)(bits >> (56 - 8*i));
process(buf); buf_len = 0;
uint8_t full[32];
for (int i = 0; i < 8; i++) {
full[i*4] = (uint8_t)(h[i] >> 24); full[i*4+1] = (uint8_t)(h[i] >> 16);
full[i*4+2] = (uint8_t)(h[i] >> 8); full[i*4+3] = (uint8_t)(h[i]);
}
if (out_len > 32) out_len = 32;
memcpy(out, full, out_len);
}
// Standard HMAC-SHA256 (kept correct for API parity; OTA tests don't exercise it).
void resetHMAC(const uint8_t* key, size_t keyLen) {
memset(hmac_key, 0, 64);
if (keyLen > 64) { SHA256 t; t.update(key, keyLen); t.finalize(hmac_key, 32); }
else memcpy(hmac_key, key, keyLen);
reset();
uint8_t ipad[64];
for (int i = 0; i < 64; i++) ipad[i] = hmac_key[i] ^ 0x36;
update(ipad, 64);
}
void finalizeHMAC(const uint8_t* key, size_t keyLen, uint8_t* out, size_t out_len) {
(void)key; (void)keyLen;
uint8_t inner[32]; finalize(inner, 32);
uint8_t opad[64];
for (int i = 0; i < 64; i++) opad[i] = hmac_key[i] ^ 0x5c;
reset(); update(opad, 64); update(inner, 32); finalize(out, out_len);
}
};