Skip to content

Commit 468114f

Browse files
authored
Merge pull request #541 from Cypherock/feat/inheritance/seed-based-wallet-auth
feat(app): Add seed based wallet auth
2 parents eaf3df4 + 6acb3f5 commit 468114f

File tree

7 files changed

+195
-64
lines changed

7 files changed

+195
-64
lines changed

apps/inheritance_app/inheritance_auth_wallet.c

Lines changed: 145 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "inheritance/core.pb.h"
2323
#include "inheritance_api.h"
2424
#include "inheritance_priv.h"
25+
#include "reconstruct_wallet_flow.h"
2526
#include "status_api.h"
2627
#include "ui_delay.h"
2728

@@ -83,6 +84,21 @@ static bool auth_wallet_get_entropy();
8384
*/
8485
static bool auth_wallet_get_pairs();
8586

87+
/**
88+
* @brief Signs the given challenge.
89+
*
90+
* The function generates an Ed25519 signature for the provided challenge
91+
* and verifies it against the public key.
92+
*
93+
* @return true if the signature is successfully created and verified, false
94+
* otherwise.
95+
*/
96+
static bool auth_wallet_sign_challenge(const uint8_t *unsigned_txn,
97+
const size_t unsigned_txn_size,
98+
const ed25519_secret_key private_key,
99+
const ed25519_public_key public_key,
100+
ed25519_signature signature);
101+
86102
/**
87103
* @brief Generates and verifies a digital signature for the wallet
88104
* authentication.
@@ -101,9 +117,10 @@ static bool auth_wallet_get_signature();
101117
*****************************************************************************/
102118

103119
static bool verify_auth_wallet_inputs() {
104-
if (NULL == auth->challenge || NULL == auth->wallet_id ||
105-
auth->challenge_size < CHALLENGE_SIZE_MIN ||
106-
auth->challenge_size > CHALLENGE_SIZE_MAX) {
120+
if (auth->data.challenge_size == 0 ||
121+
auth->data.challenge_size < CHALLENGE_SIZE_MIN ||
122+
auth->data.challenge_size > CHALLENGE_SIZE_MAX ||
123+
(auth->do_wallet_based == false && auth->do_seed_based == false)) {
107124
inheritance_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
108125
ERROR_DATA_FLOW_INVALID_QUERY);
109126
delay_scr_init(ui_text_inheritance_wallet_auth_fail, DELAY_TIME);
@@ -114,61 +131,119 @@ static bool verify_auth_wallet_inputs() {
114131
}
115132

116133
static bool auth_wallet_get_entropy() {
117-
secure_data_t msgs[1] = {0};
118-
msgs[0].plain_data_size = WALLET_ID_SIZE;
119-
memcpy(msgs[0].plain_data, auth->wallet_id, WALLET_ID_SIZE);
120-
121-
card_error_type_e status = card_fetch_encrypt_data(auth->wallet_id, msgs, 1);
122-
123-
delay_scr_init(ui_text_inheritance_wallet_authenticating, DELAY_SHORT);
124-
125-
if (status != CARD_OPERATION_SUCCESS ||
126-
msgs[0].encrypted_data_size > ENTROPY_SIZE_LIMIT) {
127-
inheritance_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
128-
ERROR_DATA_FLOW_INVALID_QUERY);
129-
delay_scr_init(ui_text_inheritance_wallet_auth_fail, DELAY_TIME);
130-
return false;
134+
if (auth->do_seed_based) {
135+
uint8_t seed[SIZE_SEED] = {0};
136+
if (!reconstruct_seed_without_passphrase(
137+
auth->data.wallet_id, seed, inheritance_send_error)) {
138+
memzero(seed, sizeof(seed));
139+
inheritance_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
140+
ERROR_DATA_FLOW_INVALID_QUERY);
141+
delay_scr_init(ui_text_inheritance_wallet_auth_fail, DELAY_TIME);
142+
return false;
143+
}
144+
memcpy((void *)auth->seed_based_data.entropy, seed, SIZE_SEED);
145+
auth->seed_based_data.entropy_size = SIZE_SEED;
146+
auth->seed_based_data.has_data = true;
147+
memzero(seed, sizeof(seed));
148+
// seed generation complete
149+
set_app_flow_status(INHERITANCE_AUTH_WALLET_STATUS_SEED_BASED_CARD_TAPPED);
150+
}
151+
if (auth->do_wallet_based) {
152+
secure_data_t msgs[1] = {0};
153+
msgs[0].plain_data_size = WALLET_ID_SIZE;
154+
memcpy(msgs[0].plain_data, auth->data.wallet_id, WALLET_ID_SIZE);
155+
156+
card_error_type_e status =
157+
card_fetch_encrypt_data(auth->data.wallet_id, msgs, 1);
158+
if (status != CARD_OPERATION_SUCCESS ||
159+
msgs[0].encrypted_data_size > ENTROPY_SIZE_LIMIT) {
160+
inheritance_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
161+
ERROR_DATA_FLOW_INVALID_DATA);
162+
delay_scr_init(ui_text_inheritance_wallet_auth_fail, DELAY_TIME);
163+
return false;
164+
}
165+
memcpy((void *)auth->wallet_based_data.entropy,
166+
msgs[0].encrypted_data,
167+
msgs[0].encrypted_data_size);
168+
auth->wallet_based_data.entropy_size = msgs[0].encrypted_data_size;
169+
auth->wallet_based_data.has_data = true;
170+
// wallet id encryption complete
171+
set_app_flow_status(
172+
INHERITANCE_AUTH_WALLET_STATUS_WALLET_BASED_CARD_TAPPED);
131173
}
132-
set_app_flow_status(INHERITANCE_AUTH_WALLET_STATUS_CARD_TAPPED);
133174

134-
memcpy((void *)auth->entropy,
135-
msgs[0].encrypted_data,
136-
msgs[0].encrypted_data_size);
137-
auth->entropy_size = msgs[0].encrypted_data_size;
175+
delay_scr_init(ui_text_inheritance_wallet_authenticating, DELAY_SHORT);
138176

139177
return true;
140178
}
141179

142180
static bool auth_wallet_get_pairs() {
143-
mnemonic_to_seed((char *)auth->entropy, "", auth->private_key, NULL);
144-
ed25519_publickey(auth->private_key, auth->public_key);
145-
181+
if (auth->seed_based_data.has_data) {
182+
mnemonic_to_seed((char *)auth->seed_based_data.entropy,
183+
"",
184+
auth->seed_based_data.private_key,
185+
NULL);
186+
ed25519_publickey(auth->seed_based_data.private_key,
187+
auth->seed_based_data.result.public_key);
188+
// Clear seed as soon as it is not needed
189+
memzero((void *const)auth->seed_based_data.entropy,
190+
sizeof(auth->seed_based_data.entropy));
191+
}
192+
if (auth->wallet_based_data.has_data) {
193+
mnemonic_to_seed((char *)auth->wallet_based_data.entropy,
194+
"",
195+
auth->wallet_based_data.private_key,
196+
NULL);
197+
ed25519_publickey(auth->wallet_based_data.private_key,
198+
auth->wallet_based_data.result.public_key);
199+
}
146200
return true;
147201
}
202+
static bool auth_wallet_sign_challenge(const uint8_t *unsigned_txn,
203+
const size_t unsigned_txn_size,
204+
const ed25519_secret_key private_key,
205+
const ed25519_public_key public_key,
206+
ed25519_signature signature) {
207+
ed25519_sign(
208+
unsigned_txn, unsigned_txn_size, private_key, public_key, signature);
148209

149-
static bool auth_wallet_get_signature() {
150-
const size_t unsigned_txn_size = auth->challenge_size + WALLET_ID_SIZE;
151-
uint8_t unsigned_txn[unsigned_txn_size];
152-
153-
memcpy(unsigned_txn, auth->challenge, auth->challenge_size);
154-
memcpy(unsigned_txn + auth->challenge_size, auth->wallet_id, WALLET_ID_SIZE);
155-
156-
ed25519_sign(unsigned_txn,
157-
unsigned_txn_size,
158-
auth->private_key,
159-
auth->public_key,
160-
auth->signature);
161-
162-
int valid = ed25519_sign_open(
163-
unsigned_txn, unsigned_txn_size, auth->public_key, auth->signature);
210+
int valid =
211+
ed25519_sign_open(unsigned_txn, unsigned_txn_size, public_key, signature);
164212

165213
if (0 != valid) {
166214
inheritance_send_error(ERROR_COMMON_ERROR_CORRUPT_DATA_TAG,
167215
ERROR_DATA_FLOW_INVALID_DATA);
168216
delay_scr_init(ui_text_inheritance_wallet_auth_fail, DELAY_TIME);
169217
return false;
170218
}
219+
return true;
220+
}
171221

222+
static bool auth_wallet_get_signature() {
223+
const size_t unsigned_txn_size = auth->data.challenge_size + WALLET_ID_SIZE;
224+
uint8_t unsigned_txn[unsigned_txn_size];
225+
memcpy(unsigned_txn, auth->data.challenge, auth->data.challenge_size);
226+
memcpy(unsigned_txn + auth->data.challenge_size,
227+
auth->data.wallet_id,
228+
WALLET_ID_SIZE);
229+
if (auth->do_seed_based) {
230+
if (!auth_wallet_sign_challenge(unsigned_txn,
231+
unsigned_txn_size,
232+
auth->seed_based_data.private_key,
233+
auth->seed_based_data.result.public_key,
234+
auth->seed_based_data.result.signature)) {
235+
return false;
236+
}
237+
}
238+
if (auth->do_wallet_based) {
239+
if (!auth_wallet_sign_challenge(unsigned_txn,
240+
unsigned_txn_size,
241+
auth->wallet_based_data.private_key,
242+
auth->wallet_based_data.result.public_key,
243+
auth->wallet_based_data.result.signature)) {
244+
return false;
245+
}
246+
}
172247
return true;
173248
}
174249

@@ -177,16 +252,28 @@ static bool send_result() {
177252
result.which_response = INHERITANCE_RESULT_AUTH_WALLET_TAG;
178253
result.auth_wallet.which_response =
179254
INHERITANCE_AUTH_WALLET_RESPONSE_RESULT_TAG;
180-
memcpy(result.auth_wallet.result.signature,
181-
auth->signature,
182-
sizeof(ed25519_signature));
183-
184-
if (auth->is_setup) {
185-
memcpy(result.auth_wallet.result.public_key,
186-
auth->public_key,
187-
sizeof(ed25519_public_key));
255+
if (auth->do_seed_based) {
256+
memcpy(result.auth_wallet.result.seed_based.signature,
257+
auth->seed_based_data.result.signature,
258+
sizeof(ed25519_signature));
259+
result.auth_wallet.result.has_seed_based = true;
260+
if (auth->with_public_key) {
261+
memcpy(result.auth_wallet.result.seed_based.public_key,
262+
auth->seed_based_data.result.public_key,
263+
sizeof(ed25519_public_key));
264+
}
265+
}
266+
if (auth->do_wallet_based) {
267+
memcpy(result.auth_wallet.result.wallet_based.signature,
268+
auth->wallet_based_data.result.signature,
269+
sizeof(ed25519_signature));
270+
result.auth_wallet.result.has_wallet_based = true;
271+
if (auth->with_public_key) {
272+
memcpy(result.auth_wallet.result.wallet_based.public_key,
273+
auth->wallet_based_data.result.public_key,
274+
sizeof(ed25519_public_key));
275+
}
188276
}
189-
190277
inheritance_send_result(&result);
191278
return true;
192279
}
@@ -199,13 +286,16 @@ void inheritance_auth_wallet(inheritance_query_t *query) {
199286
ASSERT(auth != NULL);
200287
memzero(auth, sizeof(auth_wallet_config_t));
201288

202-
memcpy(
203-
auth->wallet_id, query->auth_wallet.initiate.wallet_id, WALLET_ID_SIZE);
204-
auth->challenge_size = query->auth_wallet.initiate.challenge.size;
205-
memcpy(auth->challenge,
289+
memcpy(auth->data.wallet_id,
290+
query->auth_wallet.initiate.wallet_id,
291+
WALLET_ID_SIZE);
292+
auth->data.challenge_size = query->auth_wallet.initiate.challenge.size;
293+
memcpy(auth->data.challenge,
206294
query->auth_wallet.initiate.challenge.bytes,
207-
auth->challenge_size);
208-
auth->is_setup = query->auth_wallet.initiate.is_public_key;
295+
auth->data.challenge_size);
296+
auth->with_public_key = query->auth_wallet.initiate.with_public_key;
297+
auth->do_seed_based = query->auth_wallet.initiate.do_seed_based;
298+
auth->do_wallet_based = query->auth_wallet.initiate.do_wallet_based;
209299

210300
set_app_flow_status(INHERITANCE_AUTH_WALLET_STATUS_INIT);
211301
if (verify_auth_wallet_inputs() && auth_wallet_get_entropy() &&

apps/inheritance_app/inheritance_encrypt_data.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,6 @@ static bool encrypt_message_data(void) {
385385
// TODO: throw encryption failed error
386386
return false;
387387
}
388-
set_app_flow_status(INHERITANCE_AUTH_WALLET_STATUS_CARD_TAPPED);
389388
return true;
390389
}
391390

apps/inheritance_app/inheritance_priv.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define CHALLENGE_SIZE_MAX 32
2929
#define CHALLENGE_SIZE_MIN 16
3030
#define ENTROPY_SIZE_LIMIT 100
31-
31+
#define SIZE_SEED 64
3232
/*****************************************************************************
3333
* PRIVATE TYPEDEFS
3434
*****************************************************************************/
@@ -41,19 +41,32 @@ typedef enum {
4141
} auth_wallet_error_type_e;
4242

4343
#pragma pack(push, 1)
44+
typedef struct {
45+
ed25519_signature signature;
46+
ed25519_public_key public_key;
47+
} auth_wallet_result_t;
48+
4449
typedef struct {
4550
uint8_t wallet_id[WALLET_ID_SIZE];
4651
uint8_t challenge[CHALLENGE_SIZE_MAX];
4752
size_t challenge_size;
53+
} auth_wallet_data_t;
4854

55+
typedef struct {
4956
const uint8_t entropy[ENTROPY_SIZE_LIMIT];
5057
uint8_t entropy_size;
5158
ed25519_secret_key private_key;
59+
auth_wallet_result_t result;
60+
bool has_data;
61+
} auth_wallet_private_t;
5262

53-
ed25519_signature signature;
54-
ed25519_public_key public_key;
55-
56-
bool is_setup;
63+
typedef struct {
64+
auth_wallet_data_t data;
65+
auth_wallet_private_t wallet_based_data;
66+
auth_wallet_private_t seed_based_data;
67+
bool with_public_key;
68+
bool do_seed_based;
69+
bool do_wallet_based;
5770
auth_wallet_error_type_e status;
5871
} auth_wallet_config_t;
5972
#pragma pack(pop)

common/cypherock-common

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
inheritance.AuthWalletInitiateRequest.challenge type:FT_STATIC max_size:32 fixed_length:false
22
inheritance.AuthWalletInitiateRequest.wallet_id type:FT_STATIC max_size:32 fixed_length:true
3-
inheritance.AuthWalletResultResponse.public_key type:FT_STATIC max_size:32 fixed_length:true
4-
inheritance.AuthWalletResultResponse.signature type:FT_STATIC max_size:64 fixed_length:true
3+
inheritance.AuthWalletSignatureAndKey.public_key type:FT_STATIC max_size:32 fixed_length:true
4+
inheritance.AuthWalletSignatureAndKey.signature type:FT_STATIC max_size:64 fixed_length:true

src/wallet/reconstruct_wallet_flow.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,31 @@ static const char *reconstruct_wallet(const uint8_t *wallet_id,
379379
/*****************************************************************************
380380
* GLOBAL FUNCTIONS
381381
*****************************************************************************/
382+
bool reconstruct_seed_without_passphrase(const uint8_t *wallet_id,
383+
uint8_t *seed_out,
384+
rejection_cb *reject_cb) {
385+
if ((NULL == wallet_id) || (NULL == seed_out)) {
386+
return false;
387+
}
388+
389+
uint8_t result = false;
390+
391+
clear_wallet_data();
392+
mnemonic_clear();
393+
394+
const char *mnemonics = reconstruct_wallet(wallet_id, PIN_INPUT, reject_cb);
395+
396+
if (NULL != mnemonics) {
397+
mnemonic_to_seed(
398+
mnemonics, wallet_credential_data.passphrase, seed_out, NULL);
399+
result = true;
400+
}
401+
402+
mnemonic_clear();
403+
clear_wallet_data();
404+
return result;
405+
}
406+
382407
bool reconstruct_seed(const uint8_t *wallet_id,
383408
uint8_t *seed_out,
384409
rejection_cb *reject_cb) {

src/wallet/reconstruct_wallet_flow.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ bool reconstruct_seed(const uint8_t *wallet_id,
6868
uint8_t reconstruct_mnemonics(
6969
const uint8_t *wallet_id,
7070
char mnemonic_list[MAX_NUMBER_OF_MNEMONIC_WORDS][MAX_MNEMONIC_WORD_LENGTH]);
71+
72+
bool reconstruct_seed_without_passphrase(const uint8_t *wallet_id,
73+
uint8_t *seed_out,
74+
rejection_cb *reject_cb);
7175
#endif /* RECONSTRUCT_SEED_FLOW_H */

0 commit comments

Comments
 (0)