SHA256
Перенёс основной ESP32-скетч в main-device
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
# SHiNE Homeserver UI Main
|
||||
|
||||
Это основной рабочий скетч ESP32-проекта `SHiNE`.
|
||||
|
||||
Текущая каноническая точка запуска:
|
||||
|
||||
- `./burn.sh shine-homeserver-main`
|
||||
- `./burn.sh homeserver-ui`
|
||||
|
||||
Историческое имя этого скетча:
|
||||
|
||||
- `lvgl-nav-minimal-test`
|
||||
|
||||
Прежние тестовые варианты для этой платы остаются в `main-device/test_sketches/` и должны восприниматься как старые диагностические сборки, а не как основной UI.
|
||||
+3332
File diff suppressed because it is too large
Load Diff
+578
@@ -0,0 +1,578 @@
|
||||
#include "shine_secret_generation.h"
|
||||
|
||||
#include <SD_MMC.h>
|
||||
#include <Preferences.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <driver/gpio.h>
|
||||
|
||||
#define PIN_SD_CLK 2
|
||||
#define PIN_SD_CMD 1
|
||||
#define PIN_SD_D0 3
|
||||
#define SD_MEM_FILE "/argon2.bin"
|
||||
|
||||
#define A2_T 2u
|
||||
#define A2_M 65536u
|
||||
#define A2_P 1u
|
||||
#define A2_DKLEN 32u
|
||||
#define A2_SYNC 4u
|
||||
#define A2_SEG (A2_M / A2_SYNC)
|
||||
#define A2_VERSION 0x13u
|
||||
#define A2_TYPE 2u
|
||||
#define A2_BLKSZ 1024u
|
||||
#define TOTAL_FILLS (A2_T * A2_M - 2u)
|
||||
|
||||
struct B2State {
|
||||
uint64_t h[8], t[2], f[2];
|
||||
uint8_t buf[128];
|
||||
size_t buflen, outlen;
|
||||
};
|
||||
|
||||
static bool gSdReady = false;
|
||||
static bool gRunning = false;
|
||||
static bool gDone = false;
|
||||
static bool gError = false;
|
||||
static char gMessage[96] = {};
|
||||
static uint8_t gSecret[32] = {};
|
||||
static char gSecretB58[64] = {};
|
||||
static uint32_t gDoneBlocks = 0;
|
||||
static uint32_t gStartMs = 0;
|
||||
static uint32_t gCurPass = 0;
|
||||
static uint32_t gCurBlock = 2;
|
||||
static bool gInitDone = false;
|
||||
static File gSdFile;
|
||||
static uint8_t *gBufPrev = nullptr;
|
||||
static uint8_t *gBufRef = nullptr;
|
||||
static uint8_t *gBufOut = nullptr;
|
||||
static uint8_t *gBufZero = nullptr;
|
||||
static uint8_t *gBufAddr = nullptr;
|
||||
static uint32_t *gJ1Seg = nullptr;
|
||||
static uint8_t gH0[64] = {};
|
||||
static B2State gB2S;
|
||||
|
||||
#define ROTR64(x,n) (((x)>>(n))|((x)<<(64-(n))))
|
||||
static const uint64_t B2IV[8] = {
|
||||
0x6A09E667F3BCC908ULL,0xBB67AE8584CAA73BULL,
|
||||
0x3C6EF372FE94F82BULL,0xA54FF53A5F1D36F1ULL,
|
||||
0x510E527FADE682D1ULL,0x9B05688C2B3E6C1FULL,
|
||||
0x1F83D9ABFB41BD6BULL,0x5BE0CD19137E2179ULL
|
||||
};
|
||||
static const uint8_t B2SIGMA[12][16] = {
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
|
||||
{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
|
||||
{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
|
||||
{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
|
||||
{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
|
||||
{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
|
||||
{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
|
||||
{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
|
||||
{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0},
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3}
|
||||
};
|
||||
|
||||
static const char B58_ALPHA[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
static void setMessage(const char *message) {
|
||||
snprintf(gMessage, sizeof(gMessage), "%s", message ? message : "");
|
||||
}
|
||||
|
||||
static void b2_compress(B2State *S, const uint8_t *blk) {
|
||||
uint64_t m[16], v[16];
|
||||
for (int i = 0; i < 16; i++) m[i] = ((const uint64_t *)blk)[i];
|
||||
for (int i = 0; i < 8; i++) v[i] = S->h[i];
|
||||
v[8]=B2IV[0];v[9]=B2IV[1];v[10]=B2IV[2];v[11]=B2IV[3];
|
||||
v[12]=B2IV[4]^S->t[0];v[13]=B2IV[5]^S->t[1];
|
||||
v[14]=B2IV[6]^S->f[0];v[15]=B2IV[7]^S->f[1];
|
||||
#define BG(r,i,a,b,c,d) \
|
||||
v[a]+=v[b]+m[B2SIGMA[r][2*(i)]]; v[d]=ROTR64(v[d]^v[a],32); \
|
||||
v[c]+=v[d]; v[b]=ROTR64(v[b]^v[c],24); \
|
||||
v[a]+=v[b]+m[B2SIGMA[r][2*(i)+1]]; v[d]=ROTR64(v[d]^v[a],16); \
|
||||
v[c]+=v[d]; v[b]=ROTR64(v[b]^v[c],63)
|
||||
for (int r = 0; r < 12; r++) {
|
||||
BG(r,0,0,4,8,12);BG(r,1,1,5,9,13);BG(r,2,2,6,10,14);BG(r,3,3,7,11,15);
|
||||
BG(r,4,0,5,10,15);BG(r,5,1,6,11,12);BG(r,6,2,7,8,13);BG(r,7,3,4,9,14);
|
||||
}
|
||||
#undef BG
|
||||
for (int i = 0; i < 8; i++) S->h[i] ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
|
||||
static void b2_init(B2State *S, size_t outlen) {
|
||||
memset(S, 0, sizeof(*S));
|
||||
memcpy(S->h, B2IV, 64);
|
||||
S->h[0] ^= 0x01010000ULL | outlen;
|
||||
S->outlen = outlen;
|
||||
}
|
||||
|
||||
static void b2_update(B2State *S, const uint8_t *in, size_t inlen) {
|
||||
while (inlen > 0) {
|
||||
size_t fill = 128 - S->buflen;
|
||||
size_t use = inlen < fill ? inlen : fill;
|
||||
memcpy(S->buf + S->buflen, in, use);
|
||||
S->buflen += use;
|
||||
in += use;
|
||||
inlen -= use;
|
||||
if (S->buflen == 128 && inlen > 0) {
|
||||
S->t[0] += 128;
|
||||
if (S->t[0] < 128) S->t[1]++;
|
||||
b2_compress(S, S->buf);
|
||||
S->buflen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void b2_final(B2State *S, uint8_t *digest) {
|
||||
S->f[0] = ~0ULL;
|
||||
S->t[0] += S->buflen;
|
||||
if (S->t[0] < S->buflen) S->t[1]++;
|
||||
memset(S->buf + S->buflen, 0, 128 - S->buflen);
|
||||
b2_compress(S, S->buf);
|
||||
uint8_t tmp[64];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint64_t w = S->h[i];
|
||||
for (int j = 0; j < 8; j++) tmp[i * 8 + j] = (uint8_t)(w >> (j * 8));
|
||||
}
|
||||
memcpy(digest, tmp, S->outlen);
|
||||
}
|
||||
|
||||
static void b2hash(const uint8_t *in, size_t inlen, uint8_t *digest, size_t outlen) {
|
||||
b2_init(&gB2S, outlen);
|
||||
b2_update(&gB2S, in, inlen);
|
||||
b2_final(&gB2S, digest);
|
||||
}
|
||||
|
||||
static void b2long(const uint8_t *in, size_t inlen, uint8_t *digest, uint32_t outlen) {
|
||||
uint8_t lenle[4] = {(uint8_t)outlen, (uint8_t)(outlen >> 8), (uint8_t)(outlen >> 16), (uint8_t)(outlen >> 24)};
|
||||
if (outlen <= 64) {
|
||||
b2_init(&gB2S, outlen);
|
||||
b2_update(&gB2S, lenle, 4);
|
||||
b2_update(&gB2S, in, inlen);
|
||||
b2_final(&gB2S, digest);
|
||||
return;
|
||||
}
|
||||
uint8_t tmp[64];
|
||||
b2_init(&gB2S, 64);
|
||||
b2_update(&gB2S, lenle, 4);
|
||||
b2_update(&gB2S, in, inlen);
|
||||
b2_final(&gB2S, tmp);
|
||||
memcpy(digest, tmp, 32);
|
||||
digest += 32;
|
||||
uint32_t rem = outlen - 32;
|
||||
while (rem > 64) {
|
||||
b2hash(tmp, 64, tmp, 64);
|
||||
memcpy(digest, tmp, 32);
|
||||
digest += 32;
|
||||
rem -= 32;
|
||||
}
|
||||
b2hash(tmp, 64, tmp, rem);
|
||||
memcpy(digest, tmp, rem);
|
||||
}
|
||||
|
||||
#define A2G(a,b,c,d) do{ \
|
||||
(a)+=(b)+2*((a)&0xFFFFFFFFULL)*((b)&0xFFFFFFFFULL); \
|
||||
(d)=ROTR64((d)^(a),32); \
|
||||
(c)+=(d)+2*((c)&0xFFFFFFFFULL)*((d)&0xFFFFFFFFULL); \
|
||||
(b)=ROTR64((b)^(c),24); \
|
||||
(a)+=(b)+2*((a)&0xFFFFFFFFULL)*((b)&0xFFFFFFFFULL); \
|
||||
(d)=ROTR64((d)^(a),16); \
|
||||
(c)+=(d)+2*((c)&0xFFFFFFFFULL)*((d)&0xFFFFFFFFULL); \
|
||||
(b)=ROTR64((b)^(c),63); \
|
||||
}while(0)
|
||||
#define A2P(v) do{ \
|
||||
A2G((v)[0],(v)[4],(v)[8],(v)[12]);A2G((v)[1],(v)[5],(v)[9],(v)[13]); \
|
||||
A2G((v)[2],(v)[6],(v)[10],(v)[14]);A2G((v)[3],(v)[7],(v)[11],(v)[15]); \
|
||||
A2G((v)[0],(v)[5],(v)[10],(v)[15]);A2G((v)[1],(v)[6],(v)[11],(v)[12]); \
|
||||
A2G((v)[2],(v)[7],(v)[8],(v)[13]);A2G((v)[3],(v)[4],(v)[9],(v)[14]); \
|
||||
}while(0)
|
||||
|
||||
static void fillBlock(uint32_t prevIdx, uint32_t refIdx, uint32_t outIdx, bool xorMode) {
|
||||
gSdFile.seek((uint64_t)prevIdx * A2_BLKSZ); gSdFile.read(gBufPrev, A2_BLKSZ);
|
||||
gSdFile.seek((uint64_t)refIdx * A2_BLKSZ); gSdFile.read(gBufRef, A2_BLKSZ);
|
||||
uint64_t *R = (uint64_t *)gBufOut, *P = (uint64_t *)gBufPrev, *F = (uint64_t *)gBufRef;
|
||||
for (int i = 0; i < 128; i++) R[i] = P[i] ^ F[i];
|
||||
uint64_t *Q = (uint64_t *)gBufRef; memcpy(Q, R, A2_BLKSZ);
|
||||
for (int j = 0; j < 8; j++) A2P(&Q[16 * j]);
|
||||
uint64_t row[16];
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int k = 0; k < 8; k++) { row[2 * k] = Q[2 * i + 16 * k]; row[2 * k + 1] = Q[2 * i + 16 * k + 1]; }
|
||||
A2P(row);
|
||||
for (int k = 0; k < 8; k++) { Q[2 * i + 16 * k] = row[2 * k]; Q[2 * i + 16 * k + 1] = row[2 * k + 1]; }
|
||||
}
|
||||
for (int i = 0; i < 128; i++) R[i] = Q[i] ^ R[i];
|
||||
if (xorMode) {
|
||||
gSdFile.seek((uint64_t)outIdx * A2_BLKSZ); gSdFile.read(gBufPrev, A2_BLKSZ);
|
||||
uint64_t *O = (uint64_t *)gBufPrev; for (int i = 0; i < 128; i++) R[i] ^= O[i];
|
||||
}
|
||||
gSdFile.seek((uint64_t)outIdx * A2_BLKSZ); gSdFile.write(gBufOut, A2_BLKSZ);
|
||||
}
|
||||
|
||||
static void generateAddresses(uint32_t pass, uint32_t slice) {
|
||||
memset(gBufZero, 0, A2_BLKSZ);
|
||||
uint8_t inputBlk[A2_BLKSZ]; memset(inputBlk, 0, A2_BLKSZ);
|
||||
uint64_t *iv = (uint64_t *)inputBlk;
|
||||
iv[0]=pass;iv[1]=0;iv[2]=slice;iv[3]=A2_M;iv[4]=A2_T;iv[5]=A2_TYPE;
|
||||
uint32_t count = 0;
|
||||
for (uint32_t b = 0; b < A2_SEG; b += 128) {
|
||||
iv[6] = ++count;
|
||||
{
|
||||
uint64_t *R=(uint64_t*)gBufAddr,*Z=(uint64_t*)gBufZero,*I=iv;
|
||||
for(int i=0;i<128;i++)R[i]=Z[i]^I[i];
|
||||
uint64_t *Q=R,row[16];
|
||||
for(int j=0;j<8;j++)A2P(&Q[16*j]);
|
||||
for(int i=0;i<8;i++){
|
||||
for(int k=0;k<8;k++){row[2*k]=Q[2*i+16*k];row[2*k+1]=Q[2*i+16*k+1];}
|
||||
A2P(row);
|
||||
for(int k=0;k<8;k++){Q[2*i+16*k]=row[2*k];Q[2*i+16*k+1]=row[2*k+1];}
|
||||
}
|
||||
for(int i=0;i<128;i++)R[i]=Q[i]^(Z[i]^I[i]);
|
||||
}
|
||||
{
|
||||
uint64_t *R=(uint64_t*)gBufPrev,*Z=(uint64_t*)gBufZero,*A=(uint64_t*)gBufAddr;
|
||||
for(int i=0;i<128;i++)R[i]=Z[i]^A[i];
|
||||
uint64_t *Q=R,row[16];
|
||||
for(int j=0;j<8;j++)A2P(&Q[16*j]);
|
||||
for(int i=0;i<8;i++){
|
||||
for(int k=0;k<8;k++){row[2*k]=Q[2*i+16*k];row[2*k+1]=Q[2*i+16*k+1];}
|
||||
A2P(row);
|
||||
for(int k=0;k<8;k++){Q[2*i+16*k]=row[2*k];Q[2*i+16*k+1]=row[2*k+1];}
|
||||
}
|
||||
for(int i=0;i<128;i++)R[i]=Q[i]^(Z[i]^A[i]);
|
||||
memcpy(gBufAddr,gBufPrev,A2_BLKSZ);
|
||||
}
|
||||
uint64_t *addr=(uint64_t*)gBufAddr;
|
||||
uint32_t cnt=(b+128<=A2_SEG)?128:(A2_SEG-b);
|
||||
for(uint32_t j=0;j<cnt;j++)gJ1Seg[b+j]=(uint32_t)(addr[j]&0xFFFFFFFFULL);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t indexAlpha(uint32_t pass, uint32_t slice, uint32_t posInSlice, uint32_t J1) {
|
||||
uint32_t refAreaSize;
|
||||
if (pass == 0) {
|
||||
if (slice == 0) {
|
||||
uint32_t pos = posInSlice;
|
||||
refAreaSize = (pos < 2) ? 0 : pos - 1;
|
||||
} else {
|
||||
refAreaSize = slice * A2_SEG + posInSlice - 1;
|
||||
}
|
||||
} else {
|
||||
refAreaSize = A2_M - A2_SEG + posInSlice - 1;
|
||||
}
|
||||
if (refAreaSize == 0) refAreaSize = 1;
|
||||
uint64_t relPos = (uint64_t)J1 * J1 >> 32;
|
||||
relPos = refAreaSize - 1 - ((uint64_t)refAreaSize * relPos >> 32);
|
||||
uint32_t startPos = 0;
|
||||
if (pass != 0 && slice != A2_SYNC - 1) startPos = (slice + 1) * A2_SEG;
|
||||
return (startPos + relPos) % A2_M;
|
||||
}
|
||||
|
||||
static void sha256calc(const uint8_t *in, size_t len, uint8_t *out32) {
|
||||
mbedtls_sha256_context ctx;
|
||||
mbedtls_sha256_init(&ctx);
|
||||
mbedtls_sha256_starts(&ctx, 0);
|
||||
mbedtls_sha256_update(&ctx, in, len);
|
||||
mbedtls_sha256_finish(&ctx, out32);
|
||||
mbedtls_sha256_free(&ctx);
|
||||
}
|
||||
|
||||
static void trimInPlace(char *text) {
|
||||
if (!text) return;
|
||||
size_t len = strlen(text);
|
||||
size_t start = 0;
|
||||
while (start < len && (text[start] == ' ' || text[start] == '\t' || text[start] == '\n' || text[start] == '\r')) start++;
|
||||
size_t end = len;
|
||||
while (end > start && (text[end - 1] == ' ' || text[end - 1] == '\t' || text[end - 1] == '\n' || text[end - 1] == '\r')) end--;
|
||||
if (start > 0 && end > start) memmove(text, text + start, end - start);
|
||||
if (end <= start) { text[0] = '\0'; return; }
|
||||
text[end - start] = '\0';
|
||||
}
|
||||
|
||||
static void lowercaseAsciiInPlace(char *text) {
|
||||
if (!text) return;
|
||||
for (int i = 0; text[i]; i++) if (text[i] >= 'A' && text[i] <= 'Z') text[i] += 32;
|
||||
}
|
||||
|
||||
static void normalizeLoginInPlace(char *text) {
|
||||
trimInPlace(text);
|
||||
lowercaseAsciiInPlace(text);
|
||||
}
|
||||
|
||||
static void bytesToBase64Std(const uint8_t *data, size_t len, char *out, size_t outSz) {
|
||||
size_t b64len = 0;
|
||||
if (outSz == 0) return;
|
||||
if (mbedtls_base64_encode((uint8_t*)out, outSz, &b64len, data, len) != 0) {
|
||||
out[0] = '\0';
|
||||
return;
|
||||
}
|
||||
if (b64len >= outSz) b64len = outSz - 1;
|
||||
out[b64len] = '\0';
|
||||
}
|
||||
|
||||
static void deriveLegacyMasterSecret(const char *password, uint8_t *out32) {
|
||||
uint8_t baseHash[32];
|
||||
sha256calc((const uint8_t*)password, strlen(password), baseHash);
|
||||
char baseB64[64];
|
||||
bytesToBase64Std(baseHash, 32, baseB64, sizeof(baseB64));
|
||||
char material[96];
|
||||
snprintf(material, sizeof(material), "%smaster.secret", baseB64);
|
||||
sha256calc((const uint8_t*)material, strlen(material), out32);
|
||||
}
|
||||
|
||||
void shineSecretBase58Encode(const uint8_t *data, size_t len, char *out, size_t outSz) {
|
||||
int zeros = 0;
|
||||
while (zeros < (int)len && data[zeros] == 0) zeros++;
|
||||
uint8_t tmp[128] = {};
|
||||
int tmpLen = 0;
|
||||
for (int i = zeros; i < (int)len; i++) {
|
||||
int carry = data[i];
|
||||
for (int j = 0; j < tmpLen; j++) { carry += 256 * tmp[j]; tmp[j] = carry % 58; carry /= 58; }
|
||||
while (carry) { tmp[tmpLen++] = carry % 58; carry /= 58; }
|
||||
}
|
||||
int n = 0;
|
||||
for (int i = 0; i < zeros && n < (int)outSz - 1; i++) out[n++] = '1';
|
||||
for (int i = tmpLen - 1; i >= 0 && n < (int)outSz - 1; i--) out[n++] = B58_ALPHA[(int)tmp[i]];
|
||||
out[n] = '\0';
|
||||
}
|
||||
|
||||
bool shineSecretBase58Decode(const char *input, uint8_t *out, size_t *outLen, size_t maxOutLen, String &error) {
|
||||
error = "";
|
||||
if (!input || !*input) {
|
||||
error = "secret too short";
|
||||
return false;
|
||||
}
|
||||
size_t inLen = strlen(input);
|
||||
uint8_t tmp[256] = {};
|
||||
size_t tmpLen = 0;
|
||||
size_t zeros = 0;
|
||||
while (zeros < inLen && input[zeros] == '1') zeros++;
|
||||
|
||||
for (size_t i = zeros; i < inLen; ++i) {
|
||||
const char *pos = strchr(B58_ALPHA, input[i]);
|
||||
if (!pos) {
|
||||
error = "invalid base58";
|
||||
return false;
|
||||
}
|
||||
int carry = (int)(pos - B58_ALPHA);
|
||||
for (size_t j = 0; j < tmpLen; ++j) {
|
||||
carry += 58 * tmp[j];
|
||||
tmp[j] = carry & 0xFF;
|
||||
carry >>= 8;
|
||||
}
|
||||
while (carry > 0) {
|
||||
tmp[tmpLen++] = carry & 0xFF;
|
||||
carry >>= 8;
|
||||
if (tmpLen >= sizeof(tmp)) {
|
||||
error = "secret too long";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t decodedLen = zeros + tmpLen;
|
||||
if (decodedLen > maxOutLen) {
|
||||
error = "secret too long";
|
||||
return false;
|
||||
}
|
||||
memset(out, 0, maxOutLen);
|
||||
size_t offset = 0;
|
||||
for (size_t i = 0; i < zeros; ++i) out[offset++] = 0;
|
||||
for (size_t i = 0; i < tmpLen; ++i) out[offset + i] = tmp[tmpLen - 1 - i];
|
||||
*outLen = decodedLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void argon2Init(const char *login, const char *password) {
|
||||
char saltSrc[256];
|
||||
snprintf(saltSrc, sizeof(saltSrc), "shine-auth-v2|login=%s|suffix=master.secret", login);
|
||||
uint8_t saltHash[32]; sha256calc((uint8_t*)saltSrc, strlen(saltSrc), saltHash);
|
||||
uint8_t salt[16]; memcpy(salt, saltHash, 16);
|
||||
|
||||
char passBytes[128];
|
||||
snprintf(passBytes, sizeof(passBytes), "%s\n%s", login, password);
|
||||
uint32_t passLen = strlen(passBytes), saltLen = 16;
|
||||
|
||||
b2_init(&gB2S, 64);
|
||||
uint8_t le4[4];
|
||||
#define B2LE32(val) do{uint32_t _v=(val);le4[0]=_v;le4[1]=_v>>8;le4[2]=_v>>16;le4[3]=_v>>24;b2_update(&gB2S,le4,4);}while(0)
|
||||
B2LE32(A2_P);B2LE32(A2_DKLEN);B2LE32(A2_M);B2LE32(A2_T);
|
||||
B2LE32(A2_VERSION);B2LE32(A2_TYPE);
|
||||
B2LE32(passLen);b2_update(&gB2S,(const uint8_t*)passBytes,passLen);
|
||||
B2LE32(saltLen);b2_update(&gB2S,salt,saltLen);
|
||||
B2LE32(0);B2LE32(0);
|
||||
#undef B2LE32
|
||||
b2_final(&gB2S, gH0);
|
||||
|
||||
uint8_t input[72]; memcpy(input, gH0, 64);
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
input[64]=i;input[65]=0;input[66]=0;input[67]=0;
|
||||
input[68]=0;input[69]=0;input[70]=0;input[71]=0;
|
||||
b2long(input, 72, gBufOut, A2_BLKSZ);
|
||||
gSdFile.seek((uint64_t)i * A2_BLKSZ); gSdFile.write(gBufOut, A2_BLKSZ);
|
||||
}
|
||||
gCurPass = 0;
|
||||
gCurBlock = 2;
|
||||
gDoneBlocks = 0;
|
||||
gStartMs = millis();
|
||||
gInitDone = true;
|
||||
generateAddresses(0, 0);
|
||||
}
|
||||
|
||||
bool shineSecretInitSd(String &error) {
|
||||
error = "";
|
||||
if (gSdReady) return true;
|
||||
gpio_reset_pin(GPIO_NUM_2);
|
||||
pinMode(PIN_SD_CMD, INPUT_PULLUP);
|
||||
pinMode(PIN_SD_D0, INPUT_PULLUP);
|
||||
delay(20);
|
||||
SD_MMC.setPins(PIN_SD_CLK, PIN_SD_CMD, PIN_SD_D0);
|
||||
gSdReady = SD_MMC.begin("/sdcard", true);
|
||||
if (!gSdReady) {
|
||||
error = "SD card error";
|
||||
return false;
|
||||
}
|
||||
if (!gBufPrev) {
|
||||
gBufPrev=(uint8_t*)ps_malloc(A2_BLKSZ);
|
||||
gBufRef=(uint8_t*)ps_malloc(A2_BLKSZ);
|
||||
gBufOut=(uint8_t*)ps_malloc(A2_BLKSZ);
|
||||
gBufZero=(uint8_t*)ps_calloc(1, A2_BLKSZ);
|
||||
gBufAddr=(uint8_t*)ps_malloc(A2_BLKSZ);
|
||||
gJ1Seg=(uint32_t*)ps_malloc(A2_SEG * sizeof(uint32_t));
|
||||
}
|
||||
if (!gBufPrev || !gBufRef || !gBufOut || !gBufZero || !gBufAddr || !gJ1Seg) {
|
||||
error = "PSRAM alloc failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool shineSecretStart(const char *normalizedLogin, const char *password, String &error) {
|
||||
error = "";
|
||||
if (!shineSecretInitSd(error)) return false;
|
||||
if (!normalizedLogin || !*normalizedLogin) {
|
||||
error = "login not set";
|
||||
return false;
|
||||
}
|
||||
|
||||
char loginBuf[64];
|
||||
snprintf(loginBuf, sizeof(loginBuf), "%s", normalizedLogin);
|
||||
normalizeLoginInPlace(loginBuf);
|
||||
if (!loginBuf[0]) {
|
||||
error = "login not set";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gSdFile) gSdFile.close();
|
||||
SD_MMC.remove(SD_MEM_FILE);
|
||||
gSdFile = SD_MMC.open(SD_MEM_FILE, "w+");
|
||||
if (!gSdFile) {
|
||||
error = "SD open failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(gSecret, 0, sizeof(gSecret));
|
||||
gSecretB58[0] = '\0';
|
||||
gDone = false;
|
||||
gError = false;
|
||||
gRunning = true;
|
||||
gInitDone = false;
|
||||
setMessage("Generating secret...");
|
||||
|
||||
if (!password || !password[0]) {
|
||||
deriveLegacyMasterSecret(password ? password : "", gSecret);
|
||||
shineSecretBase58Encode(gSecret, 32, gSecretB58, sizeof(gSecretB58));
|
||||
gDone = true;
|
||||
gRunning = false;
|
||||
setMessage("Secret generated");
|
||||
gSdFile.close();
|
||||
SD_MMC.remove(SD_MEM_FILE);
|
||||
return true;
|
||||
}
|
||||
|
||||
argon2Init(loginBuf, password);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool shineSecretStep(uint32_t blocksPerTick) {
|
||||
if (!gRunning || !gInitDone) return gDone;
|
||||
bool done = false;
|
||||
for (uint32_t i = 0; i < blocksPerTick && !done; i++) {
|
||||
if (gCurPass >= A2_T) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
uint32_t blk = gCurBlock;
|
||||
uint32_t slice = blk / A2_SEG;
|
||||
uint32_t posInSlice = blk - slice * A2_SEG;
|
||||
bool xorMode = (gCurPass > 0);
|
||||
uint32_t J1;
|
||||
bool useArgon2i = (gCurPass == 0 && slice < 2);
|
||||
if (useArgon2i) {
|
||||
J1 = gJ1Seg[posInSlice];
|
||||
} else {
|
||||
uint32_t prevIdx = (blk == 0) ? A2_M - 1 : blk - 1;
|
||||
gSdFile.seek((uint64_t)prevIdx * A2_BLKSZ);
|
||||
gSdFile.read(gBufRef, 8);
|
||||
J1 = ((uint32_t*)gBufRef)[0];
|
||||
}
|
||||
uint32_t prevIdx = (blk == 0) ? A2_M - 1 : blk - 1;
|
||||
uint32_t refIdx = indexAlpha(gCurPass, slice, posInSlice, J1);
|
||||
fillBlock(prevIdx, refIdx, blk, xorMode);
|
||||
gDoneBlocks++;
|
||||
gCurBlock++;
|
||||
if (gCurBlock >= A2_M) {
|
||||
gCurBlock = 0;
|
||||
gCurPass++;
|
||||
} else {
|
||||
uint32_t newSlice = gCurBlock / A2_SEG;
|
||||
if (newSlice != slice && gCurPass == 0 && newSlice < 2) generateAddresses(gCurPass, newSlice);
|
||||
}
|
||||
done = (gCurPass >= A2_T);
|
||||
}
|
||||
|
||||
if (done) {
|
||||
gSdFile.seek((uint64_t)(A2_M - 1) * A2_BLKSZ);
|
||||
gSdFile.read(gBufOut, A2_BLKSZ);
|
||||
b2long(gBufOut, A2_BLKSZ, gSecret, A2_DKLEN);
|
||||
shineSecretBase58Encode(gSecret, 32, gSecretB58, sizeof(gSecretB58));
|
||||
gDone = true;
|
||||
gRunning = false;
|
||||
setMessage("Secret generated");
|
||||
gSdFile.close();
|
||||
SD_MMC.remove(SD_MEM_FILE);
|
||||
}
|
||||
return gDone;
|
||||
}
|
||||
|
||||
void shineSecretAbort() {
|
||||
gRunning = false;
|
||||
gDone = false;
|
||||
gError = false;
|
||||
gInitDone = false;
|
||||
gDoneBlocks = 0;
|
||||
if (gSdFile) gSdFile.close();
|
||||
if (gSdReady) SD_MMC.remove(SD_MEM_FILE);
|
||||
setMessage("Generation cancelled");
|
||||
}
|
||||
|
||||
ShineSecretGenerationStatus shineSecretStatus() {
|
||||
ShineSecretGenerationStatus status = {};
|
||||
status.running = gRunning;
|
||||
status.done = gDone;
|
||||
status.error = gError;
|
||||
status.doneBlocks = gDoneBlocks;
|
||||
status.totalBlocks = TOTAL_FILLS;
|
||||
status.elapsedSec = gStartMs == 0 ? 0 : (millis() - gStartMs) / 1000;
|
||||
snprintf(status.message, sizeof(status.message), "%s", gMessage);
|
||||
snprintf(status.secretBase58, sizeof(status.secretBase58), "%s", gSecretB58);
|
||||
return status;
|
||||
}
|
||||
|
||||
const uint8_t *shineSecretBytes() {
|
||||
return gSecret;
|
||||
}
|
||||
|
||||
const char *shineSecretBase58() {
|
||||
return gSecretB58;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct ShineSecretGenerationStatus {
|
||||
bool running;
|
||||
bool done;
|
||||
bool error;
|
||||
uint32_t doneBlocks;
|
||||
uint32_t totalBlocks;
|
||||
uint32_t elapsedSec;
|
||||
char message[96];
|
||||
char secretBase58[64];
|
||||
};
|
||||
|
||||
bool shineSecretInitSd(String &error);
|
||||
bool shineSecretStart(const char *normalizedLogin, const char *password, String &error);
|
||||
bool shineSecretStep(uint32_t blocksPerTick = 4);
|
||||
void shineSecretAbort();
|
||||
ShineSecretGenerationStatus shineSecretStatus();
|
||||
const uint8_t *shineSecretBytes();
|
||||
const char *shineSecretBase58();
|
||||
void shineSecretBase58Encode(const uint8_t *data, size_t len, char *out, size_t outSz);
|
||||
bool shineSecretBase58Decode(const char *input, uint8_t *out, size_t *outLen, size_t maxOutLen, String &error);
|
||||
Reference in New Issue
Block a user