Massive cleanup
This commit is contained in:
495
main/zk_auth.h
495
main/zk_auth.h
@@ -8,6 +8,7 @@
|
||||
#include <esp_mac.h>
|
||||
#include <esp_system.h>
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/ecdh.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
@@ -40,8 +41,6 @@ private:
|
||||
uint8_t stored_password_hash[32]; // PBKDF2 hash of the correct password
|
||||
|
||||
bool initialized;
|
||||
bool password_set;
|
||||
bool unlocked = false; // Set to true after successful authentication
|
||||
|
||||
// Convert binary to hex string
|
||||
void bin_to_hex(const uint8_t *bin, size_t bin_len, char *hex) {
|
||||
@@ -65,7 +64,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
ZKAuth() : initialized(false), password_set(false), unlocked(false) {
|
||||
ZKAuth() : initialized(false) {
|
||||
mbedtls_ecp_group_init(&grp);
|
||||
mbedtls_mpi_init(&device_private_d);
|
||||
mbedtls_ecp_point_init(&device_public_Q);
|
||||
@@ -83,60 +82,78 @@ public:
|
||||
|
||||
// Initialize the ZK authentication system
|
||||
bool init() {
|
||||
if (initialized)
|
||||
if (initialized) {
|
||||
return true;
|
||||
|
||||
// Seed the random number generator
|
||||
const char *pers = "zk_auth_esp32";
|
||||
int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
(const unsigned char *)pers, strlen(pers));
|
||||
if (ret != 0) {
|
||||
printf("mbedtls_ctr_drbg_seed failed: -0x%04x\n", -ret);
|
||||
return false;
|
||||
} else {
|
||||
initialized = true;
|
||||
printf("\n=== ZK Authentication Initialized ===\n");
|
||||
}
|
||||
|
||||
// Setup ECC group for NIST P-256 (secp256r1)
|
||||
ret = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
if (ret != 0) {
|
||||
printf("mbedtls_ecp_group_load failed: -0x%04x\n", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate device keypair
|
||||
ret = mbedtls_ecdh_gen_public(&grp, &device_private_d, &device_public_Q,
|
||||
mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (ret != 0) {
|
||||
printf("mbedtls_ecdh_gen_public failed: -0x%04x\n", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Export public key to uncompressed format (0x04 + X + Y)
|
||||
size_t olen;
|
||||
ret = mbedtls_ecp_point_write_binary(
|
||||
&grp, &device_public_Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &olen,
|
||||
device_public_key, sizeof(device_public_key));
|
||||
if (ret != 0 || olen != 65) {
|
||||
printf("mbedtls_ecp_point_write_binary failed: -0x%04x\n", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
printf("\n=== ZK Authentication Initialized ===\n");
|
||||
printf("Public Key: ");
|
||||
for (int i = 0; i < 65; i++) {
|
||||
printf("%02x", device_public_key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("=====================================\n\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper function to write a 32-bit integer in big-endian format
|
||||
void write_uint32_be(uint8_t *buf, uint32_t val) {
|
||||
buf[0] = (val >> 24) & 0xFF;
|
||||
buf[1] = (val >> 16) & 0xFF;
|
||||
buf[2] = (val >> 8) & 0xFF;
|
||||
buf[3] = val & 0xFF;
|
||||
}
|
||||
|
||||
// Function to generate the authorized_keys string
|
||||
void generate_ssh_authorized_key(const uint8_t *atec_pubkey) {
|
||||
uint8_t ssh_blob[104];
|
||||
uint32_t offset = 0;
|
||||
|
||||
// 1. Key Type
|
||||
const char *key_type = "ecdsa-sha2-nistp256";
|
||||
write_uint32_be(&ssh_blob[offset], 19);
|
||||
offset += 4;
|
||||
memcpy(&ssh_blob[offset], key_type, 19);
|
||||
offset += 19;
|
||||
|
||||
// 2. Curve Name
|
||||
const char *curve_name = "nistp256";
|
||||
write_uint32_be(&ssh_blob[offset], 8);
|
||||
offset += 4;
|
||||
memcpy(&ssh_blob[offset], curve_name, 8);
|
||||
offset += 8;
|
||||
|
||||
// 3. Public Key (Uncompressed format: 0x04 + 64 bytes X/Y)
|
||||
write_uint32_be(&ssh_blob[offset], 65);
|
||||
offset += 4;
|
||||
ssh_blob[offset++] = 0x04;
|
||||
memcpy(&ssh_blob[offset], atec_pubkey, 64);
|
||||
offset += 64;
|
||||
|
||||
// 4. Base64 Encode the blob
|
||||
size_t b64_len = 0;
|
||||
// Call once to get required length
|
||||
mbedtls_base64_encode(NULL, 0, &b64_len, ssh_blob, 104);
|
||||
|
||||
unsigned char b64_out[b64_len];
|
||||
// Call again to actually encode
|
||||
mbedtls_base64_encode(b64_out, b64_len, &b64_len, ssh_blob, 104);
|
||||
|
||||
// 5. Print out the final authorized_keys line
|
||||
printf("ecdsa-sha2-nistp256 %s esp32-atecc608b\n", b64_out);
|
||||
}
|
||||
|
||||
// Get device identity (for /api/identity endpoint)
|
||||
char *get_identity_json() {
|
||||
char pubkey_hex[131]; // 65 bytes * 2 + null
|
||||
bin_to_hex(device_public_key, 65, pubkey_hex);
|
||||
char pubkey_hex[131]; // 65 bytes * 2 + null
|
||||
uint8_t atec_pubkey[64]; // 65 bytes * 2 + null
|
||||
uint8_t standard_pubkey[65];
|
||||
standard_pubkey[0] = 0x04;
|
||||
// Get public key from ATECC608B and convert to hex
|
||||
ATCA_STATUS status = atcab_get_pubkey(0, atec_pubkey);
|
||||
if (status != ATCA_SUCCESS) {
|
||||
printf("Failed to read public key from ATECC608B: 0x%02X\n", status);
|
||||
}
|
||||
|
||||
generate_ssh_authorized_key(atec_pubkey);
|
||||
|
||||
memcpy(&standard_pubkey[1], atec_pubkey, 64);
|
||||
bin_to_hex(standard_pubkey, 65, pubkey_hex);
|
||||
|
||||
// Get MAC address to use as salt
|
||||
uint8_t mac[6];
|
||||
@@ -152,384 +169,6 @@ public:
|
||||
cJSON_Delete(root);
|
||||
return json_str;
|
||||
}
|
||||
|
||||
void my_host_check_mac(const uint8_t *target_key, const uint8_t *tempkey,
|
||||
const uint8_t *other_data, const uint8_t *sn,
|
||||
uint8_t *out_mac) {
|
||||
// See section 11.2 of the ATECC608B datasheet CheckMac message format
|
||||
uint8_t msg[88] = {0};
|
||||
memcpy(&msg[0], target_key, 32);
|
||||
memcpy(&msg[32], tempkey, 32);
|
||||
memcpy(&msg[64], &other_data[0], 4);
|
||||
memset(&msg[68], 0, 8);
|
||||
memcpy(&msg[76], &other_data[4], 3);
|
||||
msg[79] = sn[8];
|
||||
memcpy(&msg[80], &other_data[7], 4);
|
||||
msg[84] = sn[0];
|
||||
msg[85] = sn[1];
|
||||
memcpy(&msg[86], &other_data[11], 2);
|
||||
// Hash the exact 88 bytes using the ESP32's hardware accelerator
|
||||
mbedtls_sha256(msg, sizeof(msg), out_mac, 0);
|
||||
}
|
||||
|
||||
bool verify_key(const uint8_t *received_key, size_t key_len) {
|
||||
(void)key_len;
|
||||
if (received_key == NULL)
|
||||
return false;
|
||||
|
||||
ATCA_STATUS status;
|
||||
|
||||
bool latch_status = false;
|
||||
status = atcab_info_get_latch(&latch_status);
|
||||
|
||||
printf("Device Latch Status: %s (0x%02X)\n",
|
||||
latch_status ? "LATCHED" : "UNLATCHED", latch_status);
|
||||
|
||||
uint8_t sn[ATCA_SERIAL_NUM_SIZE] = {0};
|
||||
status = atcab_read_serial_number(sn);
|
||||
if (status != ATCA_SUCCESS) {
|
||||
printf("Failed to read Serial Number\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t nonce_num_in[20] = {0xAA, 0xBB, 0xCC, 0xDD};
|
||||
uint8_t rand_out[32] = {0};
|
||||
uint8_t slot10_mac[32] = {0};
|
||||
uint8_t other_data_10[13] = "TangActivate";
|
||||
struct atca_temp_key temp_key;
|
||||
memset(&temp_key, 0, sizeof(temp_key));
|
||||
|
||||
status = atcab_nonce_rand(nonce_num_in, rand_out);
|
||||
|
||||
// Print the nonce output for debugging
|
||||
if (status != ATCA_SUCCESS) {
|
||||
printf("Slot 10 Nonce failed: 0x%02X\n", status);
|
||||
} else {
|
||||
// Compute the TempKey on the ESP32
|
||||
struct atca_nonce_in_out nonce_params;
|
||||
memset(&nonce_params, 0, sizeof(nonce_params));
|
||||
nonce_params.mode = 0x00;
|
||||
nonce_params.num_in = nonce_num_in;
|
||||
nonce_params.rand_out = rand_out;
|
||||
nonce_params.temp_key = &temp_key;
|
||||
|
||||
atcah_nonce(&nonce_params);
|
||||
|
||||
// Host calculates MAC using the calculated TempKey as the challenge
|
||||
my_host_check_mac(received_key, temp_key.value, other_data_10, sn,
|
||||
slot10_mac);
|
||||
|
||||
// See section 11.2 of the ATECC608B datasheet CheckMac message format
|
||||
status = atcab_checkmac(0x01, 10, NULL, slot10_mac, other_data_10);
|
||||
if (status == ATCA_SUCCESS) {
|
||||
printf("Slot 10 CheckMac: PASSED\n");
|
||||
} else if (status == (ATCA_STATUS)ATCA_CHECKMAC_VERIFY_FAILED) {
|
||||
// 0xD1 (-47 / 0xFFFFFFD1) see atca_status.h
|
||||
printf("Slot 10 CheckMac: ACCESS DENIED (Wrong Password)\n");
|
||||
} else {
|
||||
printf("Slot 10 CheckMac: HARDWARE ERROR (0x%02X)\n", status);
|
||||
}
|
||||
}
|
||||
status = atcab_info_set_latch(true);
|
||||
|
||||
if (status != ATCA_SUCCESS) {
|
||||
printf("Failed to latch device: 0x%02X\n", status);
|
||||
}
|
||||
|
||||
atcab_info_get_latch(&latch_status);
|
||||
printf("Device Latch Status after setting: %s (0x%02X)\n",
|
||||
latch_status ? "LATCHED" : "UNLATCHED", latch_status);
|
||||
|
||||
return (status == ATCA_SUCCESS);
|
||||
}
|
||||
|
||||
// Process unlock request with ECIES tunnel
|
||||
char *process_unlock(const char *json_payload, bool *success_out) {
|
||||
*success_out = false;
|
||||
|
||||
if (!initialized) {
|
||||
return strdup("{\"error\":\"Not initialized\"}");
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
cJSON *doc = cJSON_Parse(json_payload);
|
||||
if (doc == NULL) {
|
||||
const char *error_ptr = cJSON_GetErrorPtr();
|
||||
if (error_ptr != NULL) {
|
||||
printf("JSON parse error before: %s\n", error_ptr);
|
||||
}
|
||||
return strdup("{\"error\":\"Invalid JSON\"}");
|
||||
}
|
||||
|
||||
cJSON *client_pub_item = cJSON_GetObjectItem(doc, "clientPub");
|
||||
cJSON *encrypted_blob_item = cJSON_GetObjectItem(doc, "blob");
|
||||
|
||||
const char *client_pub_hex = NULL;
|
||||
const char *encrypted_blob_hex = NULL;
|
||||
|
||||
if (cJSON_IsString(client_pub_item))
|
||||
client_pub_hex = client_pub_item->valuestring;
|
||||
if (cJSON_IsString(encrypted_blob_item))
|
||||
encrypted_blob_hex = encrypted_blob_item->valuestring;
|
||||
|
||||
if (!client_pub_hex || !encrypted_blob_hex) {
|
||||
cJSON_Delete(doc);
|
||||
return strdup("{\"error\":\"Missing required fields\"}");
|
||||
}
|
||||
|
||||
printf("\n=== Processing Unlock Request ===\n");
|
||||
printf("Client Public Key: %s\n", client_pub_hex);
|
||||
printf("Encrypted Blob: %s\n", encrypted_blob_hex);
|
||||
|
||||
// Convert client public key from hex
|
||||
size_t client_pub_len = strlen(client_pub_hex) / 2;
|
||||
uint8_t *client_pub_bin = (uint8_t *)malloc(client_pub_len);
|
||||
if (!hex_to_bin(client_pub_hex, client_pub_bin, client_pub_len)) {
|
||||
free(client_pub_bin);
|
||||
cJSON_Delete(doc);
|
||||
return strdup("{\"error\":\"Invalid client public key format\"}");
|
||||
}
|
||||
|
||||
// Parse client public key point
|
||||
mbedtls_ecp_point client_point;
|
||||
mbedtls_ecp_point_init(&client_point);
|
||||
|
||||
int ret = mbedtls_ecp_point_read_binary(&grp, &client_point, client_pub_bin,
|
||||
client_pub_len);
|
||||
free(client_pub_bin);
|
||||
|
||||
if (ret != 0) {
|
||||
mbedtls_ecp_point_free(&client_point);
|
||||
cJSON_Delete(doc);
|
||||
printf("Failed to parse client key: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"Invalid client public key\"}");
|
||||
}
|
||||
|
||||
// Compute shared secret using ECDH
|
||||
mbedtls_mpi shared_secret_mpi;
|
||||
mbedtls_mpi_init(&shared_secret_mpi);
|
||||
|
||||
ret = mbedtls_ecdh_compute_shared(&grp, &shared_secret_mpi, &client_point,
|
||||
&device_private_d,
|
||||
mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
|
||||
mbedtls_ecp_point_free(&client_point);
|
||||
|
||||
if (ret != 0) {
|
||||
mbedtls_mpi_free(&shared_secret_mpi);
|
||||
cJSON_Delete(doc);
|
||||
printf("ECDH computation failed: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"ECDH failed\"}");
|
||||
}
|
||||
|
||||
// Export shared secret to binary
|
||||
uint8_t shared_secret_raw[32];
|
||||
ret = mbedtls_mpi_write_binary(&shared_secret_mpi, shared_secret_raw, 32);
|
||||
mbedtls_mpi_free(&shared_secret_mpi);
|
||||
|
||||
if (ret != 0) {
|
||||
cJSON_Delete(doc);
|
||||
printf("Shared secret export failed: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"Shared secret export failed\"}");
|
||||
}
|
||||
|
||||
printf("Shared Secret (raw): ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("%02x", shared_secret_raw[i]);
|
||||
printf("\n");
|
||||
|
||||
// Derive separate keys for encryption and authentication
|
||||
// This prevents key reuse vulnerabilities
|
||||
const mbedtls_md_info_t *md_info =
|
||||
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
|
||||
// Encryption key: SHA256("encryption" || shared_secret)
|
||||
uint8_t enc_key[32];
|
||||
mbedtls_md_context_t md_ctx;
|
||||
mbedtls_md_init(&md_ctx);
|
||||
mbedtls_md_setup(&md_ctx, md_info, 0);
|
||||
mbedtls_md_starts(&md_ctx);
|
||||
mbedtls_md_update(&md_ctx, (const uint8_t *)"encryption", 10);
|
||||
mbedtls_md_update(&md_ctx, shared_secret_raw, 32);
|
||||
mbedtls_md_finish(&md_ctx, enc_key);
|
||||
|
||||
// MAC key: SHA256("authentication" || shared_secret)
|
||||
uint8_t mac_key[32];
|
||||
mbedtls_md_starts(&md_ctx);
|
||||
mbedtls_md_update(&md_ctx, (const uint8_t *)"authentication", 14);
|
||||
mbedtls_md_update(&md_ctx, shared_secret_raw, 32);
|
||||
mbedtls_md_finish(&md_ctx, mac_key);
|
||||
mbedtls_md_free(&md_ctx);
|
||||
|
||||
printf("Encryption Key: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("%02x", enc_key[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("MAC Key: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("%02x", mac_key[i]);
|
||||
printf("\n");
|
||||
|
||||
// Securely wipe the raw shared secret
|
||||
memset(shared_secret_raw, 0, 32);
|
||||
|
||||
// Convert encrypted blob from hex
|
||||
// Format: IV (16 bytes) + Ciphertext (32 bytes) + HMAC (32 bytes) = 80
|
||||
// bytes
|
||||
size_t encrypted_len = strlen(encrypted_blob_hex) / 2;
|
||||
uint8_t *encrypted_blob = (uint8_t *)malloc(encrypted_len);
|
||||
if (!hex_to_bin(encrypted_blob_hex, encrypted_blob, encrypted_len)) {
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
memset(mac_key, 0, 32);
|
||||
cJSON_Delete(doc);
|
||||
return strdup("{\"error\":\"Invalid blob format\"}");
|
||||
}
|
||||
|
||||
// Verify blob length: IV(16) + Ciphertext(32) + HMAC(32) = 80 bytes
|
||||
if (encrypted_len != 80) {
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
memset(mac_key, 0, 32);
|
||||
cJSON_Delete(doc);
|
||||
printf("Expected 80 bytes, got %d\n", encrypted_len);
|
||||
return strdup("{\"error\":\"Invalid blob length\"}");
|
||||
}
|
||||
|
||||
// Extract components from blob
|
||||
uint8_t *iv = encrypted_blob; // First 16 bytes
|
||||
uint8_t *ciphertext = encrypted_blob + 16; // Next 32 bytes
|
||||
uint8_t *received_hmac = encrypted_blob + 48; // Last 32 bytes
|
||||
|
||||
printf("IV: ");
|
||||
for (int i = 0; i < 16; i++)
|
||||
printf("%02x", iv[i]);
|
||||
printf("\n");
|
||||
|
||||
printf("Received HMAC: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("%02x", received_hmac[i]);
|
||||
printf("\n");
|
||||
|
||||
// ⚠️ CRITICAL: Verify HMAC BEFORE decrypting
|
||||
// This prevents padding oracle attacks and ensures data authenticity
|
||||
uint8_t computed_hmac[32];
|
||||
ret = mbedtls_md_hmac(md_info, mac_key, 32, encrypted_blob, 48,
|
||||
computed_hmac);
|
||||
|
||||
if (ret != 0) {
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
memset(mac_key, 0, 32);
|
||||
cJSON_Delete(doc);
|
||||
printf("HMAC computation failed: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"HMAC computation failed\"}");
|
||||
}
|
||||
|
||||
printf("Computed HMAC: ");
|
||||
for (int i = 0; i < 32; i++)
|
||||
printf("%02x", computed_hmac[i]);
|
||||
printf("\n");
|
||||
|
||||
// Constant-time comparison to prevent timing attacks
|
||||
int hmac_result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
hmac_result |= received_hmac[i] ^ computed_hmac[i];
|
||||
}
|
||||
|
||||
// Wipe MAC key after verification
|
||||
memset(mac_key, 0, 32);
|
||||
|
||||
if (hmac_result != 0) {
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
cJSON_Delete(doc);
|
||||
printf("❌ HMAC verification FAILED - ciphertext was modified or wrong "
|
||||
"key!\n");
|
||||
return strdup("{\"error\":\"Authentication failed - data tampered or "
|
||||
"wrong password\"}");
|
||||
}
|
||||
|
||||
printf("✅ HMAC verified - data is authentic\n");
|
||||
|
||||
// Now safe to decrypt (HMAC passed)
|
||||
mbedtls_aes_context aes;
|
||||
mbedtls_aes_init(&aes);
|
||||
|
||||
ret = mbedtls_aes_setkey_dec(&aes, enc_key, 256);
|
||||
if (ret != 0) {
|
||||
mbedtls_aes_free(&aes);
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
cJSON_Delete(doc);
|
||||
printf("AES setkey failed: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"AES setup failed\"}");
|
||||
}
|
||||
|
||||
uint8_t *decrypted_data = (uint8_t *)malloc(32);
|
||||
uint8_t iv_copy[16];
|
||||
memcpy(iv_copy, iv, 16); // CBC mode modifies IV
|
||||
|
||||
ret = mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT,
|
||||
32, // data length
|
||||
iv_copy, // IV (will be modified)
|
||||
ciphertext, // input
|
||||
decrypted_data); // output
|
||||
|
||||
mbedtls_aes_free(&aes);
|
||||
free(encrypted_blob);
|
||||
memset(enc_key, 0, 32);
|
||||
|
||||
if (ret != 0) {
|
||||
free(decrypted_data);
|
||||
cJSON_Delete(doc);
|
||||
printf("AES decrypt failed: -0x%04x\n", -ret);
|
||||
return strdup("{\"error\":\"Decryption failed\"}");
|
||||
}
|
||||
|
||||
// Extract the derived key (PBKDF2 hash, 32 bytes)
|
||||
printf("\n=== DECRYPTED DERIVED KEY ===\n");
|
||||
printf("Key (hex): ");
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
printf("%02x", decrypted_data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
printf("=============================\n\n");
|
||||
|
||||
// Verify the decrypted key against stored password hash
|
||||
bool verification_result = verify_key(decrypted_data, 32);
|
||||
|
||||
cJSON *resp_doc = cJSON_CreateObject();
|
||||
cJSON_AddBoolToObject(resp_doc, "success", verification_result);
|
||||
|
||||
if (verification_result) {
|
||||
printf("✅ Password verification SUCCESSFUL\n");
|
||||
unlocked = true;
|
||||
cJSON_AddStringToObject(resp_doc, "message", "Unlock successful");
|
||||
} else {
|
||||
printf("❌ Password verification FAILED\n");
|
||||
unlocked = false;
|
||||
cJSON_AddStringToObject(resp_doc, "error", "Invalid password");
|
||||
}
|
||||
|
||||
char *response_str = cJSON_PrintUnformatted(resp_doc);
|
||||
cJSON_Delete(resp_doc);
|
||||
cJSON_Delete(doc);
|
||||
|
||||
// Securely wipe decrypted data
|
||||
memset(decrypted_data, 0, 32);
|
||||
free(decrypted_data);
|
||||
|
||||
*success_out = verification_result;
|
||||
return response_str;
|
||||
}
|
||||
|
||||
// Check if device is unlocked
|
||||
bool is_unlocked() const { return unlocked; }
|
||||
|
||||
// Lock the device
|
||||
void lock() { unlocked = false; }
|
||||
};
|
||||
|
||||
#endif // ZK_AUTH_H
|
||||
|
||||
Reference in New Issue
Block a user