What changed, and why it matters
This firmware update fixes a bug in how the Keystone 3 hardware wallet handles TON (The Open Network) wallet setup. The changes remove several safety checks and replace safer string/buffer functions with less safe ones, while also restructuring how TON entropy and seed generation errors are handled. The commit title says it fixes a TON wallet bug, but the diff itself mostly removes defensive coding patterns rather than adding them. Without more context, it is unclear whether the change fully resolves the underlying issue or introduces new risks.
Treat this commit as a functional bug fix that reduces defensive coding. The project should review the removed safety checks—especially the dropped entropy-length validation and the unsafe string copies—and consider reintroducing bounded copies and error checks. Users relying on TON wallets should ensure they are on the latest firmware and monitor Keystone's release notes for any security advisories.
Security signals we found
Removal of entropy length validation in TON mnemonic import
Replacement of strncpy_s/strcpy_s with strcpy in multiple paths
Removal of NULL checks after cJSON_Parse and other operations
Inline expansion of previously abstracted crypto derivation helpers
Removal of error-code checks on flash erase operations
Removal of master-key derivation error handling in TempAccountPublicInfo
Changes to TON chain handling in public key derivation and wallet management
Evidence from the diff
The patch modifies two files: account_public_info.c and keystore.c. In keystore.c, SaveNewTonMnemonic no longer validates that the TON mnemonic entropy length matches TON_ENTROPY_LEN, and it converts a CHECK_ERRCODE_BREAK macro for seed generation into an explicit if/break. In account_public_info.c, the patch inlines and removes helper functions (DeriveMasterKeysIfNeeded, DeriveChainXpub, EraseFlashRange, WritePublicJsonAndHash), removes several NULL and error checks, and replaces safer string functions (strncpy_s, strcpy_s) with unsafe ones (strcpy). It also changes JSON handling to use lower-level cJSON calls and removes fallback object creation when parsing fails. The TON-specific logic is adjusted so TON_CHECKSUM and TON_NATIVE chains are skipped during xpub derivation, and TON is explicitly set as ‘managed’ in receive-index initialization.
Changed components
TON wallet creation/import (src/managers/keystore.c)Account public key derivation and flash storage (src/crypto/account_public_info.c)Multi-sig wallet string handlingReceive index/path JSON persistenceInspect captured patch +161 / −194
diff --git a/src/crypto/account_public_info.c b/src/crypto/account_public_info.c
index 76d92d2..1075430 100644
--- a/src/crypto/account_public_info.c
+++ b/src/crypto/account_public_info.c
@@ -62,11 +62,6 @@ static void CleanupJson(cJSON* json);
static void FreePublicKeyRam(void);
static void PrintInfo(void);
static void SetIsTempAccount(bool isTemp);
-static SimpleResponse_c_char *ProcessKeyType(uint8_t *seed, int len, int cryptoKey, const char *path, void *icarusMasterKey, void *ledgerBitbox02MasterKey);
-static int32_t DeriveMasterKeysIfNeeded(bool isBip39, uint8_t *entropy, uint8_t entropyLen, uint8_t accountIndex,
- SimpleResponse_c_char **outCip3, SimpleResponse_c_char **outLedger);
-static SimpleResponse_c_char* DeriveChainXpub(int chainIndex, const uint8_t *seed, int seedLen, const char *password,
- const char *icarusMasterKey, const char *ledgerBitbox02Key, bool isSlip39);
#ifdef BTC_ONLY
static void LoadCurrentAccountMultiReceiveIndex(void);
@@ -87,8 +82,7 @@ static void LoadCurrentAccountMultiReceiveIndex(void)
if (GetCurrenMultisigWalletByIndex(i) == NULL) {
continue;
}
- strncpy_s(g_multiSigReceiveIndex[i].verifyCode, sizeof(g_multiSigReceiveIndex[i].verifyCode),
- GetCurrenMultisigWalletByIndex(i)->verifyCode, sizeof(g_multiSigReceiveIndex[i].verifyCode) - 1);
+ strcpy(g_multiSigReceiveIndex[i].verifyCode, GetCurrenMultisigWalletByIndex(i)->verifyCode);
}
}
@@ -243,8 +237,7 @@ void SetAccountMultiReceiveIndex(uint32_t index, char *verifyCode)
for (int i = 0; i < MAX_MULTI_SIG_WALLET_NUMBER; i++) {
if (strlen(g_multiSigReceiveIndex[i].verifyCode) == 0) {
g_multiSigReceiveIndex[i].index = index;
- strncpy_s(g_multiSigReceiveIndex[i].verifyCode, sizeof(g_multiSigReceiveIndex[i].verifyCode),
- verifyCode, sizeof(g_multiSigReceiveIndex[i].verifyCode) - 1);
+ strcpy(g_multiSigReceiveIndex[i].verifyCode, verifyCode);
break;
} else if (strcmp(g_multiSigReceiveIndex[i].verifyCode, verifyCode) == 0) {
g_multiSigReceiveIndex[i].index = index;
@@ -558,87 +551,6 @@ static const ChainItem_t g_chainTable[] = {
#endif
};
-static void EraseFlashRange(uint32_t startAddr, uint32_t totalSize, uint32_t sectorSize)
-{
- for (uint32_t eraseAddr = startAddr; eraseAddr < startAddr + totalSize; eraseAddr += sectorSize) {
- Gd25FlashSectorErase(eraseAddr);
- }
-}
-
-static int32_t WritePublicJsonAndHash(uint8_t accountIndex, uint32_t addr, const char *jsonString)
-{
- uint8_t hash[32];
- uint32_t size = strlen(jsonString);
- sha256((struct sha256 *)hash, jsonString, size);
- SetWalletDataHash(accountIndex, hash);
- CLEAR_ARRAY(hash);
- int len = Gd25FlashWriteBuffer(addr, (uint8_t *)&size, 4);
- ASSERT(len == 4);
- len = Gd25FlashWriteBuffer(addr + 4, (uint8_t *)jsonString, size);
- ASSERT(len == size);
- return SUCCESS_CODE;
-}
-
-static int32_t DeriveMasterKeysIfNeeded(bool isBip39, uint8_t *entropy, uint8_t entropyLen, uint8_t accountIndex,
- SimpleResponse_c_char **outCip3, SimpleResponse_c_char **outLedger)
-{
- int32_t ret = SUCCESS_CODE;
- *outCip3 = NULL;
- *outLedger = NULL;
- if (!isBip39) {
- return SUCCESS_CODE;
- }
- char *mnemonic = NULL;
- ret = bip39_mnemonic_from_bytes(NULL, entropy, entropyLen, &mnemonic);
- if (ret != SUCCESS_CODE) {
- printf("get mnemonic error\r\n");
- if (mnemonic != NULL) {
- memset_s(mnemonic, MNEMONIC_MAX_LEN, 0, strnlen_s(mnemonic, MNEMONIC_MAX_LEN));
- SRAM_FREE(mnemonic);
- }
- return ERR_GENERAL_FAIL;
- }
-
- char *passphrase = GetPassphrase(accountIndex);
- *outCip3 = get_icarus_master_key(entropy, entropyLen, passphrase);
- *outLedger = get_ledger_bitbox02_master_key(mnemonic, passphrase);
- if (mnemonic != NULL) {
- size_t mnemonic_len = strnlen_s(mnemonic, MNEMONIC_MAX_LEN);
- memset_s(mnemonic, MNEMONIC_MAX_LEN, 0, mnemonic_len);
- SRAM_FREE(mnemonic);
- }
- return SUCCESS_CODE;
-}
-
-static SimpleResponse_c_char* DeriveChainXpub(int chainIndex, const uint8_t *seed, int seedLen, const char *password,
- const char *icarusMasterKey, const char *ledgerBitbox02Key, bool isSlip39)
-{
- const int cryptoKey = g_chainTable[chainIndex].cryptoKey;
- const char *path = g_chainTable[chainIndex].path;
-#ifdef CYPHERPUNK_VERSION
- if (cryptoKey == ZCASH_UFVK_ENCRYPTED) {
- SimpleResponse_c_char *zcash_ufvk_response = derive_zcash_ufvk((uint8_t*)seed, seedLen, path);
- if (zcash_ufvk_response == NULL || zcash_ufvk_response->error_code != 0) {
- return zcash_ufvk_response;
- }
- char* zcashUfvk = zcash_ufvk_response->data;
- SimpleResponse_u8 *iv_response = rust_derive_iv_from_seed((uint8_t*)seed, seedLen);
- uint8_t iv_bytes[16];
- memcpy_s(iv_bytes, 16, iv_response->data, 16);
- free_simple_response_u8(iv_response);
- SimpleResponse_c_char* enc = rust_aes256_cbc_encrypt(zcashUfvk, password, iv_bytes, 16);
- free_simple_response_c_char(zcash_ufvk_response);
- return enc;
- }
-#endif
-#ifdef WEB3_VERSION
- if (cryptoKey == BIP32_ED25519 && isSlip39) {
- return cardano_get_pubkey_by_slip23((uint8_t*)seed, seedLen, path);
- }
-#endif
- return ProcessKeyType((uint8_t*)seed, seedLen, cryptoKey, path, (void*)icarusMasterKey, (void*)ledgerBitbox02Key);
-}
-
#ifdef WEB3_VERSION
ChainType CheckSolPathSupport(char *path)
{
@@ -880,10 +792,7 @@ void AccountPublicHomeCoinSet(WalletState_t *walletList, uint8_t count)
if (needUpdate) {
for (eraseAddr = addr; eraseAddr < addr + SPI_FLASH_SIZE_USER1_MUTABLE_DATA; eraseAddr += GD25QXX_SECTOR_SIZE) {
- if (Gd25FlashSectorErase(eraseAddr) != SUCCESS_CODE) {
- printf("Gd25FlashSectorErase error\r\n");
- return;
- }
+ Gd25FlashSectorErase(eraseAddr);
}
jsonString = cJSON_PrintBuffered(rootJson, SPI_FLASH_SIZE_USER1_MUTABLE_DATA - 4, false);
RemoveFormatChar(jsonString);
@@ -926,6 +835,7 @@ int32_t AccountPublicInfoReadFromFlash(uint8_t accountIndex, uint32_t addr)
CLEAR_ARRAY(hash);
if (GetPublicKeyFromJsonString(jsonString) == false) {
printf("GetPublicKeyFromJsonString false, need regenerate\r\n");
+ printf("err jsonString=%s\r\n", jsonString);
ret = ERR_GENERAL_FAIL;
}
@@ -968,10 +878,10 @@ int32_t AccountPublicSavePublicInfo(uint8_t accountIndex, const char *password,
SimpleResponse_c_char* cip3_response = NULL;
SimpleResponse_c_char *ledger_bitbox02_response = NULL;
if (isBip39) {
- ret = DeriveMasterKeysIfNeeded(isBip39, entropy, entropyLen, accountIndex, &cip3_response, &ledger_bitbox02_response);
- if (ret != SUCCESS_CODE) {
- break;
- }
+ char *mnemonic = NULL;
+ bip39_mnemonic_from_bytes(NULL, entropy, entropyLen, &mnemonic);
+ cip3_response = get_icarus_master_key(entropy, entropyLen, GetPassphrase(accountIndex));
+ ledger_bitbox02_response = get_ledger_bitbox02_master_key(mnemonic, GetPassphrase(accountIndex));
CHECK_AND_FREE_XPUB(cip3_response);
CHECK_AND_FREE_XPUB(ledger_bitbox02_response);
icarusMasterKey = cip3_response->data;
@@ -1009,7 +919,34 @@ int32_t AccountPublicSavePublicInfo(uint8_t accountIndex, const char *password,
if (g_chainTable[i].cryptoKey == TON_CHECKSUM || g_chainTable[i].cryptoKey == TON_NATIVE) {
continue;
}
- xPubResult = DeriveChainXpub(i, seed, seedLen, password, icarusMasterKey, ledgerBitbox02Key, isSlip39);
+#ifdef CYPHERPUNK_VERSION
+ //encrypt zcash ufvk
+ if (g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED) {
+ char* zcashUfvk = NULL;
+ SimpleResponse_c_char *zcash_ufvk_response = NULL;
+ zcash_ufvk_response = derive_zcash_ufvk(seed, len, g_chainTable[i].path);
+ CHECK_AND_FREE_XPUB(zcash_ufvk_response)
+ zcashUfvk = zcash_ufvk_response->data;
+ SimpleResponse_u8 *iv_response = rust_derive_iv_from_seed(seed, len);
+ //iv_response won't fail
+ uint8_t iv_bytes[16];
+ memcpy_s(iv_bytes, 16, iv_response->data, 16);
+ free_simple_response_u8(iv_response);
+ xPubResult = rust_aes256_cbc_encrypt(zcashUfvk, password, iv_bytes, 16);
+ } else {
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
+#endif
+#ifdef WEB3_VERSION
+ if (g_chainTable[i].cryptoKey == BIP32_ED25519 && isSlip39) {
+ xPubResult = cardano_get_pubkey_by_slip23(seed, seedLen, g_chainTable[i].path);
+ } else {
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
+#endif
+#ifdef BTC_ONLY
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+#endif
if (g_chainTable[i].cryptoKey == RSA_KEY && xPubResult == NULL) {
continue;
}
@@ -1024,18 +961,20 @@ int32_t AccountPublicSavePublicInfo(uint8_t accountIndex, const char *password,
#ifdef WEB3_VERSION
}
#endif
- EraseFlashRange(addr, SPI_FLASH_SIZE_USER1_DATA, GD25QXX_SECTOR_SIZE);
- jsonString = GetJsonStringFromPublicKey();
- if (jsonString == NULL) {
- ret = ERR_GENERAL_FAIL;
- break;
+ for (uint32_t eraseAddr = addr; eraseAddr < addr + SPI_FLASH_SIZE_USER1_DATA; eraseAddr += GD25QXX_SECTOR_SIZE) {
+ Gd25FlashSectorErase(eraseAddr);
}
+ jsonString = GetJsonStringFromPublicKey();
- WritePublicJsonAndHash(accountIndex, addr, jsonString);
- // printf("regenerate jsonString=%s\r\n", jsonString);
+ sha256((struct sha256 *)hash, jsonString, strlen(jsonString));
+ SetWalletDataHash(accountIndex, hash);
+ CLEAR_ARRAY(hash);
+ uint32_t size = strlen(jsonString);
+ int32_t len = Gd25FlashWriteBuffer(addr, (uint8_t *)&size, 4);
+ ASSERT(len == 4);
+ len = Gd25FlashWriteBuffer(addr + 4, (uint8_t *)jsonString, size);
+ ASSERT(len == size);
if (!isSlip39) {
- memset_s(cip3_response->data, strlen(cip3_response->data), 0, strlen(cip3_response->data));
- memset_s(ledger_bitbox02_response->data, strlen(ledger_bitbox02_response->data), 0, strlen(ledger_bitbox02_response->data));
free_simple_response_c_char(cip3_response);
free_simple_response_c_char(ledger_bitbox02_response);
}
@@ -1128,26 +1067,16 @@ int32_t TempAccountPublicInfo(uint8_t accountIndex, const char *password, bool s
SimpleResponse_c_char *ledger_bitbox02_response = NULL;
if (!isSlip39) {
- ret = DeriveMasterKeysIfNeeded(true, entropy, entropyLen, accountIndex, &cip3_response, &ledger_bitbox02_response);
- if (ret == SUCCESS_CODE && cip3_response && ledger_bitbox02_response) {
- if (cip3_response->error_code != 0) {
- printf("get_extended_pubkey error\r\n");
- free_simple_response_c_char(cip3_response);
- if (ledger_bitbox02_response) free_simple_response_c_char(ledger_bitbox02_response);
- return cip3_response->error_code;
- }
- if (ledger_bitbox02_response->error_code != 0) {
- printf("get_extended_pubkey error\r\n");
- if (ledger_bitbox02_response->error_message != NULL) {
- printf("error code = %d\r\nerror msg is: %s\r\n", ledger_bitbox02_response->error_code, ledger_bitbox02_response->error_message);
- }
- free_simple_response_c_char(ledger_bitbox02_response);
- free_simple_response_c_char(cip3_response);
- return ledger_bitbox02_response->error_code;
- }
+ do {
+ char *mnemonic = NULL;
+ bip39_mnemonic_from_bytes(NULL, entropy, entropyLen, &mnemonic);
+ cip3_response = get_icarus_master_key(entropy, entropyLen, GetPassphrase(accountIndex));
+ ledger_bitbox02_response = get_ledger_bitbox02_master_key(mnemonic, GetPassphrase(accountIndex));
+ CHECK_AND_FREE_XPUB(cip3_response);
+ CHECK_AND_FREE_XPUB(ledger_bitbox02_response);
icarusMasterKey = cip3_response->data;
ledgerBitbox02Key = ledger_bitbox02_response->data;
- }
+ } while (0);
}
for (i = 0; i < NUMBER_OF_ARRAYS(g_chainTable); i++) {
@@ -1157,7 +1086,35 @@ int32_t TempAccountPublicInfo(uint8_t accountIndex, const char *password, bool s
if (g_chainTable[i].cryptoKey == TON_CHECKSUM || g_chainTable[i].cryptoKey == TON_NATIVE) {
continue;
}
- xPubResult = DeriveChainXpub(i, seed, seedLen, password, icarusMasterKey, ledgerBitbox02Key, isSlip39);
+#ifdef CYPHERPUNK_VERSION
+ //encrypt zcash ufvk
+ if (g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED) {
+ char* zcashUfvk = NULL;
+ SimpleResponse_c_char *zcash_ufvk_response = NULL;
+ zcash_ufvk_response = derive_zcash_ufvk(seed, seedLen, g_chainTable[i].path);
+ CHECK_AND_FREE_XPUB(zcash_ufvk_response)
+ zcashUfvk = zcash_ufvk_response->data;
+ SimpleResponse_u8 *iv_response = rust_derive_iv_from_seed(seed, seedLen);
+ //iv_response won't fail
+ uint8_t iv_bytes[16];
+ memcpy_s(iv_bytes, 16, iv_response->data, 16);
+ free_simple_response_u8(iv_response);
+ xPubResult = rust_aes256_cbc_encrypt(zcashUfvk, password, iv_bytes, 16);
+ } else {
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
+#endif
+#ifdef WEB3_VERSION
+ if (g_chainTable[i].cryptoKey == BIP32_ED25519 && isSlip39) {
+ // ada slip23
+ xPubResult = cardano_get_pubkey_by_slip23(seed, seedLen, g_chainTable[i].path);
+ } else {
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
+#endif
+#ifdef BTC_ONLY
+ xPubResult = ProcessKeyType(seed, seedLen, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+#endif
if (g_chainTable[i].cryptoKey == RSA_KEY && xPubResult == NULL) {
continue;
}
@@ -1172,7 +1129,7 @@ int32_t TempAccountPublicInfo(uint8_t accountIndex, const char *password, bool s
}
ASSERT(xPubResult->data);
g_accountPublicInfo[i].value = SRAM_MALLOC(strnlen_s(xPubResult->data, SIMPLERESPONSE_C_CHAR_MAX_LEN) + 1);
- strcpy_s(g_accountPublicInfo[i].value, strnlen_s(xPubResult->data, SIMPLERESPONSE_C_CHAR_MAX_LEN) + 1, xPubResult->data);
+ strcpy(g_accountPublicInfo[i].value, xPubResult->data);
free_simple_response_c_char(xPubResult);
}
if (!isSlip39) {
@@ -1244,7 +1201,6 @@ uint8_t SpecifiedXPubExist(const char *value, bool isTon)
uint8_t accountIndex = 255;
for (index = 0; index < 3; index++) {
- rootJson = NULL;
addr = SPI_FLASH_ADDR_USER1_DATA + index * SPI_FLASH_ADDR_EACH_SIZE;
ret = Gd25FlashReadBuffer(addr, (uint8_t *)&size, sizeof(size));
ASSERT(ret == 4);
@@ -1381,9 +1337,8 @@ static bool GetPublicKeyFromJsonString(const char *string)
} else {
GetStringValue(chainJson, "value", pubKeyString, PUB_KEY_MAX_LENGTH);
//printf("%s pub key=%s\r\n", g_chainTable[i].name, pubKeyString);
- size_t pubKeyLen = strnlen_s(pubKeyString, PUB_KEY_MAX_LENGTH);
- g_accountPublicInfo[i].value = SRAM_MALLOC(pubKeyLen + 1);
- strcpy_s(g_accountPublicInfo[i].value, pubKeyLen + 1, pubKeyString);
+ g_accountPublicInfo[i].value = SRAM_MALLOC(strnlen_s(pubKeyString, PUB_KEY_MAX_LENGTH) + 1);
+ strcpy(g_accountPublicInfo[i].value, pubKeyString);
}
}
} while (0);
@@ -1402,18 +1357,13 @@ static char *GetJsonStringFromPublicKey(void)
chainsJson = cJSON_CreateObject();
for (i = 0; i < NUMBER_OF_ARRAYS(g_chainTable); i++) {
jsonItem = cJSON_CreateObject();
- const char* value = g_accountPublicInfo[i].value ? g_accountPublicInfo[i].value : "";
- cJSON_AddItemToObject(jsonItem, "value", cJSON_CreateString(value));
+ cJSON_AddItemToObject(jsonItem, "value", cJSON_CreateString(g_accountPublicInfo[i].value));
cJSON_AddItemToObject(jsonItem, "current", cJSON_CreateNumber(g_accountPublicInfo[i].current));
cJSON_AddItemToObject(chainsJson, g_chainTable[i].name, jsonItem);
}
cJSON_AddItemToObject(rootJson, "version", cJSON_CreateString(g_xpubInfoVersion));
cJSON_AddItemToObject(rootJson, "key", chainsJson);
retStr = cJSON_PrintBuffered(rootJson, SPI_FLASH_SIZE_USER1_DATA - 4, 0);
- if (retStr == NULL) {
- cJSON_Delete(rootJson);
- return NULL;
- }
RemoveFormatChar(retStr);
cJSON_Delete(rootJson);
return retStr;
@@ -1460,16 +1410,13 @@ bool GetFirstReceive(const char* chainName)
cJSON *rootJson = cJSON_Parse(jsonString);
SRAM_FREE(jsonString);
- if (rootJson == NULL) {
- return false;
- }
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
bool state = false;
if (item == NULL) {
printf("GetFirstReceive cannot get %s\r\n", chainName);
} else {
cJSON *firstRecv = cJSON_GetObjectItem(item, "firstRecv");
- state = firstRecv ? firstRecv->valueint : false;
+ state = firstRecv->valueint;
}
cJSON_Delete(rootJson);
return state;
@@ -1494,19 +1441,17 @@ void SetFirstReceive(const char* chainName, bool isFirst)
cJSON *rootJson = cJSON_Parse(jsonString);
SRAM_FREE(jsonString);
- if (rootJson == NULL) {
- rootJson = cJSON_CreateObject();
- }
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
if (item == NULL) {
printf("SetFirstReceive cannot get %s\r\n", chainName);
- cJSON *jsonItem = GetOrCreateObjectItem(rootJson, chainName);
- SetUintValue(jsonItem, "recvIndex", 0);
- SetUintValue(jsonItem, "recvPath", 0);
- SetBoolValue(jsonItem, "firstRecv", isFirst);
- SetBoolValue(jsonItem, "manage", true);
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0));
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(0));
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(isFirst));
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
} else {
- SetBoolValue(item, "firstRecv", isFirst);
+ cJSON_ReplaceItemInObject(item, "firstRecv", cJSON_CreateBool(isFirst));
}
for (eraseAddr = addr; eraseAddr < addr + SPI_FLASH_SIZE_USER1_MUTABLE_DATA; eraseAddr += GD25QXX_SECTOR_SIZE) {
@@ -1651,33 +1596,28 @@ int32_t MultiSigWalletGet(uint8_t accountIndex, const char *password, MultiSigWa
cJSON *order = cJSON_GetObjectItem(wallet, "order");
multiSigWalletItem->order = order->valueint;
GetStringValue(wallet, "name", strCache, MULTI_SIG_STR_CACHE_LENGTH);
- size_t nameLen = strnlen_s(strCache, MULTI_SIG_STR_CACHE_LENGTH);
- multiSigWalletItem->name = MULTI_SIG_MALLOC(nameLen + 1);
- strcpy_s(multiSigWalletItem->name, nameLen + 1, strCache);
+ multiSigWalletItem->name = MULTI_SIG_MALLOC(strlen(strCache) + 1);
+ strcpy(multiSigWalletItem->name, strCache);
GetStringValue(wallet, "verify_code", strCache, MULTI_SIG_STR_CACHE_LENGTH);
- size_t verifyCodeLen = strnlen_s(strCache, MULTI_SIG_STR_CACHE_LENGTH);
- multiSigWalletItem->verifyCode = MULTI_SIG_MALLOC(verifyCodeLen + 1);
- strcpy_s(multiSigWalletItem->verifyCode, verifyCodeLen + 1, strCache);
+ multiSigWalletItem->verifyCode = MULTI_SIG_MALLOC(strlen(strCache) + 1);
+ strcpy(multiSigWalletItem->verifyCode, strCache);
GetStringValue(wallet, "verify_without_mfp", strCache, MULTI_SIG_STR_CACHE_LENGTH);
- size_t verifyWithoutMfpLen = strnlen_s(strCache, MULTI_SIG_STR_CACHE_LENGTH);
- multiSigWalletItem->verifyWithoutMfp = MULTI_SIG_MALLOC(verifyWithoutMfpLen + 1);
- strcpy_s(multiSigWalletItem->verifyWithoutMfp, verifyWithoutMfpLen + 1, strCache);
+ multiSigWalletItem->verifyWithoutMfp = MULTI_SIG_MALLOC(strlen(strCache) + 1);
+ strcpy(multiSigWalletItem->verifyWithoutMfp, strCache);
cJSON *network = cJSON_GetObjectItem(wallet, "network");
multiSigWalletItem->network = network->valueint;
GetStringValue(wallet, "wallet_config", strCache, MULTI_SIG_STR_CACHE_LENGTH);
- size_t walletConfigLen = strnlen_s(strCache, MULTI_SIG_STR_CACHE_LENGTH);
- multiSigWalletItem->walletConfig = MULTI_SIG_MALLOC(walletConfigLen + 1);
- strcpy_s(multiSigWalletItem->walletConfig, walletConfigLen + 1, strCache);
+ multiSigWalletItem->walletConfig = MULTI_SIG_MALLOC(strlen(strCache) + 1);
+ strcpy(multiSigWalletItem->walletConfig, strCache);
GetStringValue(wallet, "format", strCache, MULTI_SIG_STR_CACHE_LENGTH);
- size_t formatLen = strnlen_s(strCache, MULTI_SIG_STR_CACHE_LENGTH);
- multiSigWalletItem->format = MULTI_SIG_MALLOC(formatLen + 1);
- strcpy_s(multiSigWalletItem->format, formatLen + 1, strCache);
+ multiSigWalletItem->format = MULTI_SIG_MALLOC(strlen(strCache) + 1);
+ strcpy(multiSigWalletItem->format, strCache);
cJSON *passphrase = cJSON_GetObjectItem(wallet, "passphrase");
multiSigWalletItem->passphrase = passphrase ? passphrase->valueint : 0;
@@ -1698,14 +1638,21 @@ uint32_t GetAccountReceiveIndex(const char* chainName)
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
if (item == NULL) {
printf("receive index cannot get %s\r\n", chainName);
- cJSON *jsonItem = GetOrCreateObjectItem(rootJson, chainName);
- SetUintValue(jsonItem, "recvIndex", 0); // recvIndex is the address index
- SetUintValue(jsonItem, "recvPath", 0); // recvPath is the derivation path type
- SetBoolValue(jsonItem, "firstRecv", true); // firstRecv is the first receive address
- bool manage = (!strcmp(chainName, "TON")) || (!strcmp(chainName, "BTC")) || (!strcmp(chainName, "ETH"));
- SetBoolValue(jsonItem, "manage", manage);
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0)); // recvIndex is the address index
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(0)); // recvPath is the derivation path type
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(true)); // firstRecv is the first receive address
+ if (!strcmp(chainName, "TON")) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else if ((!strcmp(chainName, "BTC") || !strcmp(chainName, "ETH"))) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(false));
+ }
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
} else {
- index = GetUintValue(item, "recvIndex", 0);
+ cJSON *recvIndex = cJSON_GetObjectItem(item, "recvIndex");
+ index = recvIndex ? recvIndex->valueint : 0;
}
if (!PassphraseExist(GetCurrentAccountIndex())) {
@@ -1719,8 +1666,17 @@ void SetAccountReceiveIndex(const char* chainName, uint32_t index)
uint32_t addr;
cJSON *rootJson = ReadAndParseAccountJson(&addr, NULL);
- cJSON *item = GetOrCreateObjectItem(rootJson, chainName);
- SetUintValue(item, "recvIndex", index);
+ cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
+ if (item == NULL) {
+ printf("SetAccountReceiveIndex cannot get %s\r\n", chainName);
+ }
+
+ cJSON *recvIndex = cJSON_GetObjectItem(item, "recvIndex");
+ if (recvIndex != NULL) {
+ cJSON_ReplaceItemInObject(item, "recvIndex", cJSON_CreateNumber(index));
+ } else {
+ cJSON_AddItemToObject(item, "recvIndex", cJSON_CreateNumber(index));
+ }
if (!PassphraseExist(GetCurrentAccountIndex())) {
WriteJsonToFlash(addr, rootJson);
@@ -1735,15 +1691,21 @@ uint32_t GetAccountReceivePath(const char* chainName)
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
if (item == NULL) {
- printf("GetAccountReceivePath index cannot get %s\r\n", chainName);
- cJSON *jsonItem = GetOrCreateObjectItem(rootJson, chainName);
- SetUintValue(jsonItem, "recvIndex", 0); // address index
- SetUintValue(jsonItem, "recvPath", 0); // derivation path type
- SetBoolValue(jsonItem, "firstRecv", true);
- bool manage = (!strcmp(chainName, "TON")) || (!strcmp(chainName, "BTC")) || (!strcmp(chainName, "ETH"));
- SetBoolValue(jsonItem, "manage", manage);
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0)); // recvIndex is the address index
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(0)); // recvPath is the derivation path type
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(true)); // firstRecv is the first receive address
+ if (!strcmp(chainName, "TON")) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else if ((!strcmp(chainName, "BTC") || !strcmp(chainName, "ETH"))) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(false));
+ }
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
} else {
- index = GetUintValue(item, "recvPath", 0);
+ cJSON *recvPath = cJSON_GetObjectItem(item, "recvPath");
+ index = recvPath ? recvPath->valueint : 0;
}
if (!PassphraseExist(GetCurrentAccountIndex())) {
cJSON_Delete(rootJson);
@@ -1762,15 +1724,21 @@ void SetAccountReceivePath(const char* chainName, uint32_t index)
if (!PassphraseExist(GetCurrentAccountIndex())) {
cJSON_Delete(rootJson);
} else {
- cJSON *jsonItem = GetOrCreateObjectItem(rootJson, chainName);
- SetUintValue(jsonItem, "recvIndex", 0); // address index
- SetUintValue(jsonItem, "recvPath", index); // derivation path type
- SetBoolValue(jsonItem, "firstRecv", false);
- SetBoolValue(jsonItem, "manage", false);
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0)); // recvIndex is the address index
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(index)); // recvPath is the derivation path type
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(false)); // firstRecv is the first receive address
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(false));
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
}
return;
}
- SetUintValue(item, "recvPath", index);
+ cJSON *recvPath = cJSON_GetObjectItem(item, "recvPath");
+ if (recvPath != NULL) {
+ cJSON_ReplaceItemInObject(item, "recvPath", cJSON_CreateNumber(index));
+ } else {
+ cJSON_AddItemToObject(item, "recvPath", cJSON_CreateNumber(index));
+ }
WriteJsonToFlash(addr, rootJson);
if (!PassphraseExist(GetCurrentAccountIndex())) {
@@ -2002,9 +1970,6 @@ static cJSON* ReadAndParseAccountJson(uint32_t *outAddr, uint32_t *outSize)
rootJson = cJSON_Parse(jsonString);
SRAM_FREE(jsonString);
- if (rootJson == NULL) {
- rootJson = cJSON_CreateObject();
- }
if (outAddr) *outAddr = addr;
if (outSize) *outSize = size;
diff --git a/src/managers/keystore.c b/src/managers/keystore.c
index e456b00..3cb3b7d 100644
--- a/src/managers/keystore.c
+++ b/src/managers/keystore.c
@@ -723,7 +723,6 @@ int32_t SaveNewTonMnemonic(uint8_t accountIndex, const char *mnemonic, const cha
ret = CheckPasswordExisted(password, 255);
CHECK_ERRCODE_BREAK("check repeat password", ret);
VecFFI_u8 *result = ton_mnemonic_to_entropy(mnemonic);
- CHECK_ERRCODE_BREAK("ton_mnemonic_to_entropy", TON_ENTROPY_LEN == result->size);
memcpy_s(entropy, sizeof(entropy), result->data, result->size);
free_VecFFI_u8(result);
memcpy_s(accountSecret.entropy, sizeof(accountSecret.entropy), entropy, 32);
@@ -731,7 +730,10 @@ int32_t SaveNewTonMnemonic(uint8_t accountIndex, const char *mnemonic, const cha
accountSecret.entropyLen = 32;
SimpleResponse_u8 *resultSeed = ton_entropy_to_seed(entropy, 64);
- CHECK_ERRCODE_BREAK("ton_entropy_to_seed", resultSeed->error_code);
+ if (resultSeed->error_code != 0) {
+ ret = resultSeed->error_code;
+ break;
+ }
memcpy_s(seed, sizeof(seed), resultSeed->data, SEED_LEN);
free_VecFFI_u8(resultSeed);
memcpy_s(accountSecret.seed, sizeof(accountSecret.seed), seed, SEED_LEN);
Why this scored 56/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.