diff --git a/Makefile b/Makefile index e60c8af..9978fa8 100644 --- a/Makefile +++ b/Makefile @@ -32,11 +32,11 @@ ICONNAME = images/icon_monero.gif endif APPVERSION_M=1 -APPVERSION_N=0 -APPVERSION_P=1 +APPVERSION_N=1 +APPVERSION_P=3 APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P) -SPECVERSION="0.x.0" +SPECVERSION="0.9.0" DEFINES += $(MONERO_CONFIG) MONERO_VERSION=$(APPVERSION) MONERO_NAME=$(APPNAME) SPEC_VERSION=$(SPECVERSION) @@ -65,7 +65,7 @@ DEFINES += UNUSED\(x\)=\(void\)x DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += CUSTOM_IO_APDU_BUFFER_SIZE=\(255+5+64\) -DEFINES += HAVE_USB_CLASS_CCID +#DEFINES += HAVE_USB_CLASS_CCID #DEFINES += IOCRYPT @@ -94,6 +94,8 @@ CFLAGS += -O3 -Os AS := $(GCCPATH)arm-none-eabi-gcc LD := $(GCCPATH)arm-none-eabi-gcc +SCRIPT_LD:=script.ld + #LDFLAGS += -O0 -gdwarf-2 -gstrict-dwarf LDFLAGS += -O3 -Os LDLIBS += -lm -lgcc -lc diff --git a/README.md b/README.md index d63d183..868fc0d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,43 @@ Monero wallet application for Ledger Blue and Nano S -# Revision +# Revision + +## v1.1.3 + +- Remove rolling address display +- Allow STEALTH instruction outside TX +- Doc fix + +## v1.1.2 + +Fix stack overflow for 1.5.5 SDK + +## v1.1.1 + +Allow transaction parsing when screen is locked + +## v1.1.0 + +Initial Release + +Targeted Client: Monero 0.13.0.0+ + +- Security fix: Screen lock management +- Optimisation: New protocol V2 for future +- Fix bug in large amount display that was truncated +- Remove confirmation for zero amount (fake sweep change) +- Better handling for change address to not display them +- Dual id (PIN based) management +- Add onscreen seed words display + + +## v1.0.0 + +Initial Release + +Targeted Client: Monero 0.13.0.0+ + ## v 0.12.4 / Beta 5 @@ -30,7 +66,7 @@ Targeted Client: Monero 0.12.1 ## v 0.12.1 / Beta 2 Targeted Client: Monero 0.12.1 - + - Add second PIN support - Remove key storage in NVRAM, always recompute secret key at boot - Export secret viewkey, with agreement of user, to speed up tx scan @@ -41,4 +77,4 @@ Targeted Client: Monero 0.12.1 Targeted Client: Monero 0.12.0 -- Initial Beta. \ No newline at end of file +- Initial Beta. diff --git a/doc/user/bolos-app-monero.rst b/doc/user/bolos-app-monero.rst index a0827ed..a9913b5 100644 --- a/doc/user/bolos-app-monero.rst +++ b/doc/user/bolos-app-monero.rst @@ -100,38 +100,17 @@ System Configuration Linux ~~~~~ -The following packages must be installed: pcsc-tools pcscd libpcsclite1:amd64 . - -You have to have to add the NanoS to /etc/libccid_Info.plist - - In ifdVendorID add the entry 0x2C97 - In ifdProductID add the entry 0x0001 - In ifdFriendlyName add the entry Ledger Token - -These 3 entries must be added at the end of each list. +TO BE REWRITE FOR HID MAC ~~~ -The SmartCard service must be installed. See https://smartcardservices.github.io/ - -1. First it is necessary to [disable SIP](https://developer.apple.com/library/mac/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html) That doesn't allow the editing of files in /usr/. - -2. You have to add the Nano S to /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist - - - In ifdVendorID add the entry 0x2C97 - In ifdProductID add the entry 0x0001 - In ifdFriendlyName add the entry Ledger Token - -This 3 entries must be added at the end of each list. - -3. [Enable SIP](https://developer.apple.com/library/content/documentation/Security/Conceptual/System_Integrity_Protection_Guide/ConfiguringSystemIntegrityProtection/ConfiguringSystemIntegrityProtection.html) +TO BE REWRITE FOR HID Windows ~~~~~~~ -SmartCard service should be already installed. Maybe you have to start it. +TO BE REWRITE FOR HID diff --git a/script.ld b/script.ld new file mode 100644 index 0000000..dea1fe5 --- /dev/null +++ b/script.ld @@ -0,0 +1,170 @@ +/******************************************************************************* +* Ledger Blue - Secure firmware +* (c) 2016, 2017, 2018, 2019 Ledger +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +********************************************************************************/ + +/** + * Global chip memory layout and constants + * + */ + +MEMORY +{ + DISCARD (rwx) : ORIGIN = 0xd0000000, LENGTH = 1M + + FLASH (rx) : ORIGIN = 0xc0d00000, LENGTH = 400K + SRAM (rwx) : ORIGIN = 0x20001800, LENGTH = 4K +} + +PAGE_SIZE = 64; +STACK_SIZE = 768; +END_STACK = ORIGIN(SRAM) + LENGTH(SRAM); + +SECTIONS +{ + ENTRY(main) + + /****************************************************************/ + /* This section locates the code in FLASH */ + /****************************************************************/ + + /** put text in Flash memory, VMA will be equal to LMA */ + .text : + { + /* provide start code symbol, shall be zero */ + _text = .; + _nvram = .; + + PROVIDE(_setjmp = setjmp); /*thanks clang*/ + + /* ensure main is always @ 0xC0D00000 */ + *(.boot*) + + /* place the other code and rodata defined BUT nvram variables that are displaced in a r/w area */ + *(.text*) + *(.rodata) + *(.rodata.[^N]*) /*.data.rel.ro* not here to detect invalid PIC usage */ + *(.rodata.N[^_]*) + + . = ALIGN(4); + + /* all code placed */ + _etext = .; + + . = ALIGN(PAGE_SIZE); + + _nvram_data = .; + + /* NVM data (ex-filesystem) */ + *(.bss.N_* .rodata.N_*) + + . = ALIGN(PAGE_SIZE); + _install_parameters = .; + PROVIDE(N_install_parameters = .); + _envram = .; + _nvram_data_size = _envram - _nvram_data; + + } > FLASH = 0x00 + + .data (NOLOAD): + { + . = ALIGN(4); + + /** + * Place RAM initialized variables + */ + _data = .; + + *(vtable) + *(.data*) + + _edata = .; + + } > DISCARD /*> SRAM AT>FLASH = 0x00 */ + + .bss : + { + /** + * Place RAM uninitialized variables + */ + _bss = .; + *(.bss*) + _ebss = .; + + + /** + * Reserve stack size + */ + . = ALIGN(4); + app_stack_canary = .; + PROVIDE(app_stack_canary = .); + . += 4; + _stack_validation = .; + . = _stack_validation + STACK_SIZE; + _stack = ABSOLUTE(END_STACK) - STACK_SIZE; + PROVIDE( _stack = ABSOLUTE(END_STACK) - STACK_SIZE); + _estack = ABSOLUTE(END_STACK); + PROVIDE( _estack = ABSOLUTE(END_STACK) ); + + } > SRAM = 0x00 + + /****************************************************************/ + /* DEBUG */ + /****************************************************************/ + + /* remove the debugging information from the standard libraries */ + DEBUG (NOLOAD) : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + +} diff --git a/src/monero_api.h b/src/monero_api.h index 91c1e79..c01f33b 100644 --- a/src/monero_api.h +++ b/src/monero_api.h @@ -47,6 +47,7 @@ int monero_apdu_get_subaddress_spend_public_key(void); int monero_apdu_get_subaddress_secret_key(void); int monero_apdu_open_tx(void); +void monero_reset_tx(void); int monero_apdu_open_subtx(void) ; int monero_apdu_set_signature_mode(void) ; int monero_apdu_stealth(void); @@ -162,12 +163,13 @@ int monero_hash(unsigned int algo, cx_hash_t * hasher, unsigned char* buf, unsi #define monero_sha256_commitment_final(out) \ monero_hash_final((cx_hash_t *)&G_monero_vstate.sha256_commitment, (out)?(out):G_monero_vstate.C) -#define monero_sha256_amount_init() \ - monero_hash_init_sha256((cx_hash_t *)&G_monero_vstate.sha256_amount) -#define monero_sha256_amount_update(buf,len) \ - monero_hash_update((cx_hash_t *)&G_monero_vstate.sha256_amount, (buf), (len)) -#define monero_sha256_amount_final(out) \ - monero_hash_final((cx_hash_t *)&G_monero_vstate.sha256_amount, (out)?(out):G_monero_vstate.KV) +#define monero_sha256_outkeys_init() \ + monero_hash_init_sha256((cx_hash_t *)&G_monero_vstate.sha256_out_keys) +#define monero_sha256_outkeys_update(buf,len) \ + monero_hash_update((cx_hash_t *)&G_monero_vstate.sha256_out_keys, (buf), (len)) +#define monero_sha256_outkeys_final(out) \ + monero_hash_final((cx_hash_t *)&G_monero_vstate.sha256_out_keys, (out)?(out):G_monero_vstate.OUTK) + /** * LE-7-bits encoding. High bit set says one more byte to decode. diff --git a/src/monero_blind.c b/src/monero_blind.c index 5ffbe8f..c0907b9 100644 --- a/src/monero_blind.c +++ b/src/monero_blind.c @@ -33,11 +33,6 @@ int monero_apdu_blind() { monero_io_discard(1); - //Update Hkv - monero_sha256_amount_update(AKout,32); - monero_sha256_amount_update(k,32); - monero_sha256_amount_update(v,32); - //blind mask monero_hash_to_scalar(AKout, AKout); monero_addm(k,k,AKout); diff --git a/src/monero_dispatch.c b/src/monero_dispatch.c index 4df58b3..25d5aae 100644 --- a/src/monero_dispatch.c +++ b/src/monero_dispatch.c @@ -19,32 +19,100 @@ #include "monero_api.h" #include "monero_vars.h" -int monero_dispatch() { - int sw; +void check_potocol() { + /* the first command enforce the protocol version until application quits */ + switch(G_monero_vstate.io_protocol_version) { + case 0x00: /* the first one: PCSC epoch */ + case 0x02: /* protocol V2 */ + if (G_monero_vstate.protocol == 0xff) { + G_monero_vstate.protocol = G_monero_vstate.io_protocol_version; + } + if (G_monero_vstate.protocol == G_monero_vstate.io_protocol_version) { + break; + } + //unknown protocol or hot protocol switch is not allowed + //FALL THROUGH - if (os_global_pin_is_validated() != PIN_VERIFIED) { - THROW(SW_SECURITY_STATUS_NOT_SATISFIED); - return SW_SECURITY_STATUS_NOT_SATISFIED; + default: + THROW(SW_CLA_NOT_SUPPORTED); + return ; } - if (G_monero_vstate.key_set == 0) { +} + +void check_ins_access() { + + if (G_monero_vstate.key_set != 1) { THROW(SW_CONDITIONS_NOT_SATISFIED); - return SW_SECURITY_STATUS_NOT_SATISFIED; + return; } - if ((G_monero_vstate.io_cla != 0x00) && (G_monero_vstate.io_cla != 0x10)) { - THROW(SW_CLA_NOT_SUPPORTED); - return SW_CLA_NOT_SUPPORTED; + switch (G_monero_vstate.io_ins) { + case INS_RESET: + case INS_PUT_KEY: + case INS_GET_KEY: + case INS_VERIFY_KEY: + case INS_GET_CHACHA8_PREKEY: + case INS_GEN_KEY_DERIVATION: + case INS_DERIVATION_TO_SCALAR: + case INS_DERIVE_PUBLIC_KEY: + case INS_DERIVE_SECRET_KEY: + case INS_GEN_KEY_IMAGE: + case INS_SECRET_KEY_TO_PUBLIC_KEY: + case INS_SECRET_KEY_ADD: + case INS_SECRET_KEY_SUB: + case INS_GENERATE_KEYPAIR: + case INS_SECRET_SCAL_MUL_KEY: + case INS_SECRET_SCAL_MUL_BASE: + case INS_DERIVE_SUBADDRESS_PUBLIC_KEY: + case INS_GET_SUBADDRESS: + case INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY: + case INS_GET_SUBADDRESS_SECRET_KEY: + case INS_MANAGE_SEEDWORDS: + case INS_UNBLIND: + case INS_STEALTH: + return; + + case INS_OPEN_TX: + case INS_SET_SIGNATURE_MODE: + if (os_global_pin_is_validated() != PIN_VERIFIED) { + break; + } + return; + + case INS_CLOSE_TX: + case INS_GEN_TXOUT_KEYS: + case INS_BLIND: + case INS_VALIDATE: + case INS_MLSAG: + if ((os_global_pin_is_validated() != PIN_VERIFIED) || + (G_monero_vstate.tx_in_progress != 1)) { + break; + } + return; } + THROW(SW_CONDITIONS_NOT_SATISFIED); + return; + +} + +int monero_dispatch() { + + int sw; + + check_potocol(); + check_ins_access(); + if (G_monero_vstate.io_ins == INS_RESET) { - monero_io_discard(0); + monero_init(); return 0x9000; } - G_monero_vstate.options = monero_io_fetch_u8(); + G_monero_vstate.options = monero_io_fetch_u8(); + sw = 0x6F01; switch (G_monero_vstate.io_ins) { @@ -139,6 +207,11 @@ int monero_dispatch() { sw = monero_apdu_get_subaddress_secret_key(); break; + /*--- TX OUT KEYS --- */ + case INS_GEN_TXOUT_KEYS: + sw = monero_apu_generate_txout_keys(); + break; + /* --- BLIND --- */ case INS_BLIND: sw = monero_apdu_blind(); diff --git a/src/monero_init.c b/src/monero_init.c index 47cd45e..1b961dd 100644 --- a/src/monero_init.c +++ b/src/monero_init.c @@ -38,16 +38,16 @@ void monero_init() { monero_install(MAINNET); } + G_monero_vstate.protocol = 0xff; + //generate key protection monero_aes_generate(&G_monero_vstate.spk); //load key monero_init_private_key(); - monero_ecmul_G(G_monero_vstate.A, G_monero_vstate.a); - monero_ecmul_G(G_monero_vstate.B, G_monero_vstate.b); //ux conf monero_init_ux(); // Let's go! - G_monero_vstate.state = 42; + G_monero_vstate.state = STATE_IDLE; } /* ----------------------------------------------------------------------- */ @@ -75,6 +75,7 @@ void monero_init_private_key() { switch(N_monero_pstate->key_mode) { case KEY_MODE_SEED: os_perso_derive_node_bip32(CX_CURVE_SECP256K1, path, 5 , seed, G_monero_vstate.a); + monero_keccak_F(seed,32,G_monero_vstate.b); monero_reduce(G_monero_vstate.b,G_monero_vstate.b); monero_keccak_F(G_monero_vstate.b,32,G_monero_vstate.a); diff --git a/src/monero_io.c b/src/monero_io.c index b0fc142..8c877ff 100644 --- a/src/monero_io.c +++ b/src/monero_io.c @@ -334,42 +334,18 @@ int monero_io_fetch_nv(unsigned char* buffer, int len) { int monero_io_do(unsigned int io_flags) { - //if pending input chaining - if (G_monero_vstate.io_cla & 0x01) { - goto in_chaining; - } - - + + // if IO_ASYNCH_REPLY has been set, + // monero_io_exchange will return when IO_RETURN_AFTER_TX will set in ui if (io_flags & IO_ASYNCH_REPLY) { - // if IO_ASYNCH_REPLY has been set, - // monero_io_exchange will return when IO_RETURN_AFTER_TX will set in ui monero_io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, 0); - } else { - // --- full out chaining --- + } + //else send data now + else { G_monero_vstate.io_offset = 0; - while(G_monero_vstate.io_length > MAX_OUT) { - unsigned int tx,xx; - //send chunk - tx = MAX_OUT-2; - os_memmove(G_io_apdu_buffer, G_monero_vstate.io_buffer+G_monero_vstate.io_offset, tx); - G_monero_vstate.io_length -= tx; - G_monero_vstate.io_offset += tx; - G_io_apdu_buffer[tx] = 0x61; - if (G_monero_vstate.io_length > MAX_OUT-2) { - xx = MAX_OUT-2; - } else { - xx = G_monero_vstate.io_length-2; - } - G_io_apdu_buffer[tx+1] = xx; - monero_io_exchange(CHANNEL_APDU, tx+2); - //check get response - if ((G_io_apdu_buffer[0] != 0x00) || - (G_io_apdu_buffer[1] != 0xc0) || - (G_io_apdu_buffer[2] != 0x00) || - (G_io_apdu_buffer[3] != 0x00) ) { - THROW(SW_COMMAND_NOT_ALLOWED); - return 0; - } + if(G_monero_vstate.io_length > MAX_OUT) { + THROW(SW_FILE_FULL); + return SW_FILE_FULL; } os_memmove(G_io_apdu_buffer, G_monero_vstate.io_buffer+G_monero_vstate.io_offset, G_monero_vstate.io_length); @@ -377,55 +353,23 @@ int monero_io_do(unsigned int io_flags) { monero_io_exchange(CHANNEL_APDU |IO_RETURN_AFTER_TX, G_monero_vstate.io_length); return 0; } else { - monero_io_exchange(CHANNEL_APDU, G_monero_vstate.io_length); + monero_io_exchange(CHANNEL_APDU, G_monero_vstate.io_length); } } - //--- full in chaining --- + //--- set up received data --- G_monero_vstate.io_offset = 0; G_monero_vstate.io_length = 0; - G_monero_vstate.io_cla = G_io_apdu_buffer[0]; + G_monero_vstate.io_protocol_version = G_io_apdu_buffer[0]; G_monero_vstate.io_ins = G_io_apdu_buffer[1]; G_monero_vstate.io_p1 = G_io_apdu_buffer[2]; G_monero_vstate.io_p2 = G_io_apdu_buffer[3]; G_monero_vstate.io_lc = 0; G_monero_vstate.io_le = 0; - switch (G_monero_vstate.io_ins) { - - case INS_GET_RESPONSE: - G_monero_vstate.io_le = G_io_apdu_buffer[4]; - break; - - default: - G_monero_vstate.io_lc = G_io_apdu_buffer[4]; - os_memmove(G_monero_vstate.io_buffer, G_io_apdu_buffer+5, G_monero_vstate.io_lc); - G_monero_vstate.io_length = G_monero_vstate.io_lc; - break; - } - - while(G_monero_vstate.io_cla & 0x10) { - - G_io_apdu_buffer[0] = 0x90; - G_io_apdu_buffer[1] = 0x00; - monero_io_exchange(CHANNEL_APDU, 2); - in_chaining: - if (((G_io_apdu_buffer[0] & 0xEF) != (G_monero_vstate.io_cla& 0xEF)) || - (G_io_apdu_buffer[1] != G_monero_vstate.io_ins) || - (G_io_apdu_buffer[2] != G_monero_vstate.io_p1) || - (G_io_apdu_buffer[3] != G_monero_vstate.io_p2) ) { - THROW(SW_COMMAND_NOT_ALLOWED); - return SW_COMMAND_NOT_ALLOWED; - } - G_monero_vstate.io_cla = G_io_apdu_buffer[0]; - G_monero_vstate.io_lc = G_io_apdu_buffer[4]; - if ((G_monero_vstate.io_length + G_monero_vstate.io_lc) > MONERO_IO_BUFFER_LENGTH) { - return 1; - } - os_memmove(G_monero_vstate.io_buffer+G_monero_vstate.io_length, G_io_apdu_buffer+5, G_monero_vstate.io_lc); - G_monero_vstate.io_length += G_monero_vstate.io_lc; - } - + G_monero_vstate.io_lc = G_io_apdu_buffer[4]; + os_memmove(G_monero_vstate.io_buffer, G_io_apdu_buffer+5, G_monero_vstate.io_lc); + G_monero_vstate.io_length = G_monero_vstate.io_lc; return 0; } diff --git a/src/monero_key.c b/src/monero_key.c index 40266e9..1e5d9b7 100644 --- a/src/monero_key.c +++ b/src/monero_key.c @@ -610,3 +610,94 @@ int monero_apdu_get_subaddress_secret_key(/*const crypto::secret_key& sec, const monero_io_insert_encrypt(sub_sec,32); return SW_OK; } + + +/* ----------------------------------------------------------------------- */ +/* --- --- */ +/* ----------------------------------------------------------------------- */ +// on device: + // if need_additional + // if is_subaddress: + // additional_pub = tx_sec.Bout + // else + // additional_pub = tx_sec.G + // + // if is_change + // generate_key_derivation(derivation <- tx_sec/a, R) + // else + // generate_key_derivation(derivation <- tx_sec, Aout) + // + // if (tx_version > 1) + // derivation_to_scalar(AKout <- derivation, output_index) + // + // derive_public_key(out_eph_public_key <- derivation, output_index, Bout) + // + // hash_update(Aout, Bout, AKout, out_eph_public_key) + // + // return additional_pub, Akout, out_eph_public_key + +int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_sec, crypto::public_key Aout, crypto::public_key Bout, size_t output_index, bool is_change, bool is_subaddress, bool need_additional_key*/) { + unsigned int tx_version; + unsigned char tx_sec[32]; + unsigned char Aout[32]; + unsigned char Bout[32]; + unsigned int output_index; + unsigned char is_change; + unsigned char is_subaddress; + unsigned char need_additional_key; + unsigned char derivation[32]; + + + tx_version = monero_io_fetch_u32(); + monero_io_fetch_decrypt_key(tx_sec); + monero_io_fetch(Aout,32); + monero_io_fetch(Bout,32); + output_index = monero_io_fetch_u32(); + is_change = monero_io_fetch_u8(); + is_subaddress = monero_io_fetch_u8(); + need_additional_key = monero_io_fetch_u8(); + + + + //additional pub key + monero_io_discard(1); + + + //update outkeys hash control + if (G_monero_vstate.io_protocol_version == 2) { + monero_sha256_outkeys_update(Aout,32); + monero_sha256_outkeys_update(Bout,32); + monero_sha256_outkeys_update(&is_change,1); + } + + if (need_additional_key) { + if (is_subaddress) { + monero_ecmul_k(derivation, Bout, tx_sec); + } else { + monero_ecmul_G(derivation, tx_sec); + } + monero_io_insert(derivation,32); + } + + //derivation + if (is_change) { + monero_generate_key_derivation(derivation, G_monero_vstate.R, tx_sec); + } else { + monero_generate_key_derivation(derivation, Aout, tx_sec); + } + + //compute AKout (amount key) + monero_derivation_to_scalar(tx_sec, derivation, output_index); + if (G_monero_vstate.io_protocol_version == 2) { + monero_sha256_outkeys_update(tx_sec,32); + } + monero_io_insert_encrypt(tx_sec,32); + + + //compute ephemeral output key + monero_derive_public_key(tx_sec, derivation, output_index, Bout); + monero_io_insert(tx_sec,32); + return SW_OK; +} + + diff --git a/src/monero_main.c b/src/monero_main.c index f09a9ea..c1d326e 100644 --- a/src/monero_main.c +++ b/src/monero_main.c @@ -45,6 +45,7 @@ void monero_main(void) { } CATCH_OTHER(e) { monero_io_discard(1); + monero_reset_tx(); if ( (e & 0xFFFF0000) || ( ((e&0xF000)!=0x6000) && ((e&0xF000)!=0x9000) ) ) { monero_io_insert_u32(e); @@ -117,7 +118,8 @@ unsigned char io_event(unsigned char channel) { if (s_after == PIN_VERIFIED) { monero_init_private_key(); } else { - monero_wipe_private_key(); + ;//do nothing, allowing TX parsing in lock mode + //monero_wipe_private_key(); } } diff --git a/src/monero_open_tx.c b/src/monero_open_tx.c index 99435f2..03a7bc1 100644 --- a/src/monero_open_tx.c +++ b/src/monero_open_tx.c @@ -20,6 +20,19 @@ #include "monero_vars.h" +/* ----------------------------------------------------------------------- */ +/* --- --- */ +/* ----------------------------------------------------------------------- */ +void monero_reset_tx() { + os_memset(G_monero_vstate.r, 0, 32); + os_memset(G_monero_vstate.R, 0, 32); + monero_keccak_init_H(); + monero_sha256_commitment_init(); + monero_sha256_outkeys_init(); + G_monero_vstate.tx_in_progress = 0; + } + + /* ----------------------------------------------------------------------- */ /* --- --- */ /* ----------------------------------------------------------------------- */ @@ -31,13 +44,11 @@ int monero_apdu_open_tx() { unsigned int account; - //monero_sha256_commitment_init(); - monero_sha256_amount_init(); - account = monero_io_fetch_u32(); monero_io_discard(1); - + + monero_reset_tx(); monero_rng(G_monero_vstate.r,32); monero_reduce(G_monero_vstate.r, G_monero_vstate.r); monero_ecmul_G(G_monero_vstate.R, G_monero_vstate.r); @@ -47,6 +58,7 @@ int monero_apdu_open_tx() { #ifdef DEBUG_HWDEVICE monero_io_insert(G_monero_vstate.r,32); #endif + G_monero_vstate.tx_in_progress = 1; return SW_OK; } #undef OPTION_KEEP_r @@ -55,7 +67,9 @@ int monero_apdu_open_tx() { /* --- --- */ /* ----------------------------------------------------------------------- */ int monero_apdu_close_tx() { - monero_io_discard(0); + monero_io_discard(1); + monero_reset_tx(); + G_monero_vstate.tx_in_progress = 0; return SW_OK; } @@ -66,11 +80,7 @@ int monero_apdu_close_tx() { * Sub dest address not yet supported: P1 = 2 not supported */ int monero_abort_tx() { - os_memset(G_monero_vstate.r, 0, 32); - os_memset(G_monero_vstate.R, 0, 32); - monero_keccak_init_H(); - monero_sha256_commitment_init(); - monero_sha256_amount_init(); + monero_reset_tx(); return 0; } diff --git a/src/monero_prehash.c b/src/monero_prehash.c index e202e6d..fd49790 100644 --- a/src/monero_prehash.c +++ b/src/monero_prehash.c @@ -29,8 +29,8 @@ /* ----------------------------------------------------------------------- */ int monero_apdu_mlsag_prehash_init() { if (G_monero_vstate.io_p2 == 1) { - monero_sha256_amount_final(NULL); - monero_sha256_amount_init(); + monero_sha256_outkeys_final(NULL); + monero_sha256_outkeys_init(); monero_sha256_commitment_init(); monero_keccak_init_H(); } @@ -56,46 +56,58 @@ int monero_apdu_mlsag_prehash_init() { /* ----------------------------------------------------------------------- */ int monero_apdu_mlsag_prehash_update() { unsigned char is_subaddress; - unsigned char Aout[32]; - unsigned char Bout[32]; - #define aH Aout - #define kG Bout - #define AKout Aout - unsigned char C[32]; - unsigned char v[32]; - unsigned char k[32]; - int changed; - changed = 0; - + unsigned char *Aout; + unsigned char *Bout; + unsigned char is_change; + unsigned char AKout[32]; + unsigned char *C; + unsigned char *v; + unsigned char *k; + + unsigned char aH[32]; + unsigned char kG[32]; + + + + //fetch destination is_subaddress = monero_io_fetch_u8(); - monero_io_fetch(Aout,32); - monero_io_fetch(Bout,32); + if (G_monero_vstate.io_protocol_version == 2) { + is_change = monero_io_fetch_u8(); + } else { + is_change = 0; + } + Aout = G_monero_vstate.io_buffer+G_monero_vstate.io_offset; monero_io_fetch(NULL,32); + Bout = G_monero_vstate.io_buffer+G_monero_vstate.io_offset; monero_io_fetch(Bout,32); + /*AKout = G_monero_vstate.io_buffer+G_monero_vstate.io_offset;*/ monero_io_fetch_decrypt(AKout,32); + C = G_monero_vstate.io_buffer+G_monero_vstate.io_offset; monero_io_fetch(NULL, 32); + k = G_monero_vstate.io_buffer+G_monero_vstate.io_offset; monero_io_fetch(NULL, 32); + v = G_monero_vstate.io_buffer+G_monero_vstate.io_offset; monero_io_fetch(NULL, 32); + + monero_io_discard(0); + + if (G_monero_vstate.io_protocol_version == 2) { + monero_sha256_outkeys_update(Aout,32); + monero_sha256_outkeys_update(Bout,32); + monero_sha256_outkeys_update(&is_change,1); + monero_sha256_outkeys_update(AKout,32); + } + if (G_monero_vstate.sig_mode == TRANSACTION_CREATE_REAL) { - if (os_memcmp(Aout, G_monero_vstate.A, 32) || os_memcmp(Bout, G_monero_vstate.B, 32) ) { + if ((os_memcmp(Aout, G_monero_vstate.A, 32) == 0) && (os_memcmp(Bout, G_monero_vstate.B, 32) == 0)) { + is_change = 1; + } + if (is_change == 0) { //encode dest adress monero_base58_public_key(&G_monero_vstate.ux_address[0], Aout, Bout, is_subaddress); - } else { - changed = 1; } } - monero_io_fetch_decrypt(AKout,32); - monero_io_fetch(C,32); - monero_io_fetch(k,32); - monero_io_fetch(v,32); - - monero_io_discard(1); - + //update MLSAG prehash monero_keccak_update_H(k,32); monero_keccak_update_H(v,32); - //unblind amount, mask and update amount hash control - monero_sha256_amount_update(AKout,32); - monero_unblind(v,k, AKout); - monero_sha256_amount_update(k, 32); - monero_sha256_amount_update(v, 32); - //check C = aH+kG + monero_unblind(v,k, AKout); monero_ecmul_G(kG, k); if (!cx_math_is_zero(v, 32)) { monero_ecmul_H(aH, v); @@ -106,15 +118,17 @@ int monero_apdu_mlsag_prehash_update() { if (os_memcmp(C, k, 32)) { THROW(SW_SECURITY_COMMITMENT_CONTROL); } - //update commitment hash control monero_sha256_commitment_update(C,32); - if ((G_monero_vstate.options & IN_OPTION_MORE_COMMAND)==0) { - //finalize and check amount hash_control - monero_sha256_amount_final(k); - if (os_memcmp(k, G_monero_vstate.KV, 32)) { - THROW(SW_SECURITY_AMOUNT_CHAIN_CONTROL); + + if ((G_monero_vstate.options & IN_OPTION_MORE_COMMAND)==0) { + if (G_monero_vstate.io_protocol_version == 2) { + //finalize and check outkeys hash_control + monero_sha256_outkeys_final(k); + if (os_memcmp(k, G_monero_vstate.OUTK, 32)) { + THROW(SW_SECURITY_OUTKEYS_CHAIN_CONTROL); + } } //finalize commitment hash control monero_sha256_commitment_final(NULL); @@ -125,7 +139,7 @@ int monero_apdu_mlsag_prehash_update() { //ask user uint64_t amount; amount = monero_bamount2uint64(v); - if (!changed && amount) { + if (!is_change && amount) { monero_amount2str(amount, G_monero_vstate.ux_amount, 15); ui_menu_validation_display(0); return 0; diff --git a/src/monero_types.h b/src/monero_types.h index bcec891..4016a58 100644 --- a/src/monero_types.h +++ b/src/monero_types.h @@ -96,13 +96,14 @@ enum device_mode { struct monero_v_state_s { unsigned char state; + unsigned char protocol; /* ------------------------------------------ */ /* --- IO --- */ /* ------------------------------------------ */ /* io state*/ - unsigned char io_cla; + unsigned char io_protocol_version; unsigned char io_ins; unsigned char io_p1; unsigned char io_p2; @@ -126,18 +127,18 @@ struct monero_v_state_s { /* ------------------------------------------ */ /* --- Crypo --- */ /* ------------------------------------------ */ - unsigned char a[32]; unsigned char A[32]; unsigned char b[32]; unsigned char B[32]; - + /* SPK */ cx_aes_key_t spk; /* Tx state machine */ struct { unsigned char key_set:1; + unsigned int tx_in_progress: 1; unsigned int tx_state: 4; }; @@ -153,8 +154,8 @@ struct monero_v_state_s { unsigned char c[32]; /* -- track tx-in/out and commitment -- */ - cx_sha256_t sha256_amount; - unsigned char KV[32]; + cx_sha256_t sha256_out_keys; + unsigned char OUTK[32]; cx_sha256_t sha256_commitment; unsigned char C[32]; @@ -183,6 +184,9 @@ typedef struct monero_v_state_s monero_v_state_t; #define SIZEOF_TX_VSTATE (sizeof(monero_v_state_t) - OFFSETOF(monero_v_state_t, state)) + +#define STATE_IDLE 0xC0 + /* --- ... --- */ #define IO_OFFSET_END (unsigned int)-1 #define IO_OFFSET_MARK (unsigned int)-2 @@ -229,6 +233,7 @@ typedef struct monero_v_state_s monero_v_state_t; #define INS_STEALTH 0x76 #define INS_BLIND 0x78 #define INS_UNBLIND 0x7A +#define INS_GEN_TXOUT_KEYS 0x7B #define INS_VALIDATE 0x7C #define INS_MLSAG 0x7E #define INS_CLOSE_TX 0x80 @@ -275,6 +280,7 @@ typedef struct monero_v_state_s monero_v_state_t; #define SW_SECURITY_COMMITMENT_CONTROL 0x6911 #define SW_SECURITY_AMOUNT_CHAIN_CONTROL 0x6912 #define SW_SECURITY_COMMITMENT_CHAIN_CONTROL 0x6913 +#define SW_SECURITY_OUTKEYS_CHAIN_CONTROL 0x6914 #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 #define SW_FILE_INVALID 0x6983 diff --git a/src/monero_ux_nanos.c b/src/monero_ux_nanos.c index 5e1371a..8fcdacf 100644 --- a/src/monero_ux_nanos.c +++ b/src/monero_ux_nanos.c @@ -43,10 +43,6 @@ const bagl_element_t* ui_menu_main_preprocessor(const ux_menu_entry_t* entry, ba void ui_menu_settings_display(unsigned int value); /* ------------------------------- Helpers UX ------------------------------- */ -void ui_CCID_reset(void) { - io_usb_ccid_set_card_inserted(0); - io_usb_ccid_set_card_inserted(1); -} /* void ui_info(const char* msg1, const char* msg2, const void *menu_display, unsigned int value) { os_memset(&G_monero_vstate.ui_dogsays[0], 0, sizeof(ux_menu_entry_t)); @@ -76,7 +72,7 @@ const bagl_element_t* ui_menu_fee_validation_preprocessor(const ux_menu_entry_t* /* --- Amount --- */ if (entry == &ui_menu_fee_validation[0]) { - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { element->text = G_monero_vstate.ux_amount; } } @@ -91,7 +87,7 @@ void ui_menu_fee_validation_action(unsigned int value) { sw = SW_SECURITY_STATUS_NOT_SATISFIED; monero_abort_tx(); } - monero_io_insert_u16(sw); + monero_io_insert_u16(sw); monero_io_do(IO_RETURN_AFTER_TX); ui_menu_main_display(0); } @@ -125,12 +121,12 @@ const ux_menu_entry_t ui_menu_words[] = { const bagl_element_t* ui_menu_words_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) { if ((entry->userid >= 0) && (entry->userid <25)) { - - if(element->component.userid==0x21) { + + if(element->component.userid==0x21) { element->text = N_monero_pstate->words[entry->userid]; } - - if ((element->component.userid==0x22)&&(entry->userid<24)) { + + if ((element->component.userid==0x22)&&(entry->userid<24)) { element->text = N_monero_pstate->words[entry->userid+1]; } } @@ -167,14 +163,14 @@ const bagl_element_t* ui_menu_validation_preprocessor(const ux_menu_entry_t* ent /* --- Amount --- */ if (entry == &ui_menu_validation[0]) { - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { element->text = G_monero_vstate.ux_amount; } } #if 0 /* --- Fees --- */ if (entry == &ui_menu_validation[1]) { - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { element->text = G_monero_vstate.ux_fees; } } @@ -182,7 +178,7 @@ const bagl_element_t* ui_menu_validation_preprocessor(const ux_menu_entry_t* ent /* --- Destination --- */ if (entry == &ui_menu_validation[1]) { - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*0, 11); element->text = G_monero_vstate.ux_menu; @@ -190,40 +186,40 @@ const bagl_element_t* ui_menu_validation_preprocessor(const ux_menu_entry_t* ent } if (entry == &ui_menu_validation[2]) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; - if(element->component.userid==0x21) { - os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*1, 11); + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*1, 11); } - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*2, 11); } element->text = G_monero_vstate.ux_menu; } if (entry == &ui_menu_validation[3]) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; - if(element->component.userid==0x21) { - os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*3, 11); + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*3, 11); } - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*4, 11); } element->text = G_monero_vstate.ux_menu; } if (entry == &ui_menu_validation[4]) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; - if(element->component.userid==0x21) { - os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*5, 11); + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*5, 11); } - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*6, 11); } element->text = G_monero_vstate.ux_menu; } if (entry == &ui_menu_validation[5]) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; - if(element->component.userid==0x21) { - os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*7, 11); + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*7, 11); } - if(element->component.userid==0x22) { + if(element->component.userid==0x22) { os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*8, 7); } element->text = G_monero_vstate.ux_menu; @@ -244,7 +240,7 @@ void ui_menu_validation_action(unsigned int value) { sw = SW_SECURITY_STATUS_NOT_SATISFIED; monero_abort_tx(); } - monero_io_insert_u16(sw); + monero_io_insert_u16(sw); monero_io_do(IO_RETURN_AFTER_TX); ui_menu_main_display(0); } @@ -257,41 +253,41 @@ unsigned int ui_export_viewkey_button(unsigned int button_mask, unsigned int but const bagl_element_t ui_export_viewkey[] = { - // type userid x y w h str rad fill fg bg font_id icon_id - { {BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0}, - NULL, - 0, - 0, 0, + // type userid x y w h str rad fill fg bg font_id icon_id + { {BAGL_RECTANGLE, 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0}, + NULL, + 0, + 0, 0, NULL, NULL, NULL}, - { {BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CROSS }, - NULL, - 0, - 0, 0, + { {BAGL_ICON, 0x00, 3, 12, 7, 7, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CROSS }, + NULL, + 0, + 0, 0, NULL, NULL, NULL }, - - { {BAGL_ICON, 0x00, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CHECK }, - NULL, - 0, - 0, 0, + + { {BAGL_ICON, 0x00, 117, 13, 8, 6, 0, 0, 0, 0xFFFFFF, 0x000000, 0, BAGL_GLYPH_ICON_CHECK }, + NULL, + 0, + 0, 0, NULL, NULL, NULL }, - { {BAGL_LABELINE, 0x01, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, - G_monero_vstate.ux_menu, - 0, - 0, 0, + { {BAGL_LABELINE, 0x01, 0, 12, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, + G_monero_vstate.ux_menu, + 0, + 0, 0, NULL, NULL, NULL }, - - { {BAGL_LABELINE, 0x02, 0, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, - G_monero_vstate.ux_menu, - 0, - 0, 0, + + { {BAGL_LABELINE, 0x02, 0, 26, 128, 32, 0, 0, 0, 0xFFFFFF, 0x000000, BAGL_FONT_OPEN_SANS_EXTRABOLD_11px|BAGL_FONT_ALIGNMENT_CENTER, 0 }, + G_monero_vstate.ux_menu, + 0, + 0, 0, NULL, NULL, NULL }, - + }; void ui_export_viewkey_display(unsigned int value) { - UX_DISPLAY(ui_export_viewkey, (void*)ui_export_viewkey_prepro); + UX_DISPLAY(ui_export_viewkey, (void*)ui_export_viewkey_prepro); } unsigned int ui_export_viewkey_prepro(const bagl_element_t* element) { @@ -306,7 +302,7 @@ unsigned int ui_export_viewkey_prepro(const bagl_element_t* element) { snprintf(G_monero_vstate.ux_menu, sizeof(G_monero_vstate.ux_menu), "Please Cancel"); return 1; } - + unsigned int ui_export_viewkey_button(unsigned int button_mask, unsigned int button_mask_counter) { unsigned int sw; unsigned char x[32]; @@ -314,19 +310,19 @@ unsigned int ui_export_viewkey_button(unsigned int button_mask, unsigned int but monero_io_discard(0); os_memset(x,0,32); sw = 0x9000; - + switch(button_mask) { case BUTTON_EVT_RELEASED|BUTTON_LEFT: // CANCEL - monero_io_insert(x, 32); + monero_io_insert(x, 32); break; case BUTTON_EVT_RELEASED|BUTTON_RIGHT: // OK monero_io_insert(G_monero_vstate.a, 32); #ifdef DEBUG_HWDEVICE - monero_io_insert(G_monero_vstate.b, 32); + monero_io_insert(G_monero_vstate.b, 32); #endif break; - + default: return 0; } @@ -348,7 +344,7 @@ const ux_menu_entry_t ui_menu_network[] = { }; const bagl_element_t* ui_menu_network_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) { - os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)); + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)); if ((entry == &ui_menu_network[2]) && (element->component.userid==0x20) && (N_monero_pstate->network_id == TESTNET)) { os_memmove(G_monero_vstate.ux_menu, "Test Network ", 14); G_monero_vstate.ux_menu[13] = '+'; @@ -426,29 +422,98 @@ const ux_menu_entry_t ui_menu_info[] = { #undef STR #undef XSTR +/* ---------------------------- PUBLIC ADDRESS UX ---------------------------- */ + +void ui_menu_pubaddr_action(unsigned int value); + +const ux_menu_entry_t ui_menu_pubaddr[] = { + {NULL, NULL, 3, NULL, "XMR", "?addr.1?", 0, 0}, + {NULL, NULL, 4, NULL, "?addr.2?", "?addr.2?", 0, 0}, + {NULL, NULL, 5, NULL, "?addr.3?", "?addr.3?", 0, 0}, + {NULL, NULL, 6, NULL, "?addr.4?", "?addr.4?", 0, 0}, + {NULL, NULL, 7, NULL, "?addr.5?", "?addr.5?", 0, 0}, + {NULL, ui_menu_main_display, 0, &C_badge_back, "Back", NULL, 61, 40}, + UX_MENU_END +}; + +const bagl_element_t* ui_menu_pubaddr_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) { + + /* --- address --- */ + if (entry == &ui_menu_pubaddr[0]) { + if(element->component.userid==0x22) { + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*0, 11); + element->text = G_monero_vstate.ux_menu; + } + } + if (entry == &ui_menu_pubaddr[1]) { + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*1, 11); + } + if(element->component.userid==0x22) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*2, 11); + } + element->text = G_monero_vstate.ux_menu; + } + if (entry == &ui_menu_pubaddr[2]) { + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*3, 11); + } + if(element->component.userid==0x22) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*4, 11); + } + element->text = G_monero_vstate.ux_menu; + } + if (entry == &ui_menu_pubaddr[3]) { + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*5, 11); + } + if(element->component.userid==0x22) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*6, 11); + } + element->text = G_monero_vstate.ux_menu; + } + if (entry == &ui_menu_pubaddr[4]) { + os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)) ; + if(element->component.userid==0x21) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*7, 11); + } + if(element->component.userid==0x22) { + os_memmove(G_monero_vstate.ux_menu, G_monero_vstate.ux_address+11*8, 7); + } + element->text = G_monero_vstate.ux_menu; + } + + return element; +} + +void ui_menu_pubaddr_display(unsigned int value) { + monero_base58_public_key(G_monero_vstate.ux_address, G_monero_vstate.A,G_monero_vstate.B, 0); + UX_MENU_DISPLAY(value, ui_menu_pubaddr, ui_menu_pubaddr_preprocessor); +} + /* --------------------------------- MAIN UX --------------------------------- */ const ux_menu_entry_t ui_menu_main[] = { - {NULL, NULL, 0, NULL, "", NULL, 0, 0}, + {NULL, ui_menu_pubaddr_display, 0, NULL, "XWP", "", 0, 0}, {ui_menu_settings, NULL, 0, NULL, "Settings", NULL, 0, 0}, {ui_menu_info, NULL, 0, NULL, "About", NULL, 0, 0}, {NULL, os_sched_exit, 0, &C_icon_dashboard, "Quit app" , NULL, 50, 29}, UX_MENU_END }; -extern const uint8_t N_USBD_CfgDesc[]; + const bagl_element_t* ui_menu_main_preprocessor(const ux_menu_entry_t* entry, bagl_element_t* element) { if (entry == &ui_menu_main[0]) { - if(element->component.userid==0x20) { + if(element->component.userid==0x22) { os_memset(G_monero_vstate.ux_menu, 0, sizeof(G_monero_vstate.ux_menu)); - os_memmove(G_monero_vstate.ux_menu, "< Swap: ", 8); - monero_base58_public_key(G_monero_vstate.ux_menu+8, G_monero_vstate.A,G_monero_vstate.B, 0); - G_monero_vstate.ux_menu[8+98+0] = ' '; - G_monero_vstate.ux_menu[8+98+1] = '>'; - - element->component.stroke = 10; // 1 second stop in each way - element->component.icon_id = 48; // roundtrip speed in pixel/s + monero_base58_public_key(G_monero_vstate.ux_menu, G_monero_vstate.A,G_monero_vstate.B, 0); + os_memset(G_monero_vstate.ux_menu+5,'.',2); + os_memmove(G_monero_vstate.ux_menu+7, G_monero_vstate.ux_menu+95-5,5); + G_monero_vstate.ux_menu[12] = 0; element->text = G_monero_vstate.ux_menu; - UX_CALLBACK_SET_INTERVAL(bagl_label_roundtrip_duration_ms(element, 7)); } } return element; diff --git a/tools/python/README.md b/tools/python/README.md index e1e9dae..fa6b200 100644 --- a/tools/python/README.md +++ b/tools/python/README.md @@ -19,11 +19,11 @@ The following python package are required: - Ecpy - pycrytodome - ledgerblue - - pip3 install pycryptodomex - pip3 install ECPy - pip3 install ledgerblue - +``` + pip3 install pycryptodomex + pip3 install ECPy + pip3 install ledgerblue +``` ### Usage In tools/python/ directory: diff --git a/tools/python/src/ledger/monero/seedconv.py b/tools/python/src/ledger/monero/seedconv.py index 1b88ef0..960eaaa 100644 --- a/tools/python/src/ledger/monero/seedconv.py +++ b/tools/python/src/ledger/monero/seedconv.py @@ -24,7 +24,7 @@ from ecpy import curves from Cryptodome.Hash import keccak -from ledgerblue.comm import getDongle + from .dictionaries.languages import monero_langs @@ -35,6 +35,7 @@ MAJOR = 0 MINOR = 9 +DEBUG=False def usage(c): print(''' @@ -55,7 +56,8 @@ def banner(): '''%(MAJOR,MINOR)) def printdbg(*args): - print(*args) + if DEBUG: + print(*args) return def error(msg): @@ -302,7 +304,7 @@ def get_online_seed(lang): send_dict_chunk(dongle,lang['prefix_length'], chunk, start, cnt) print() print("Done.") - print("Your key words are avalaible on your device under 'Settings/Show keyword' menu.") + print("Your key words are avalaible on your device under 'Settings/Show 25 words' menu.") print("You can delete it at the end of keyword list.") def clear_online_seed(lang): @@ -351,6 +353,7 @@ def max_wlen(): usage(0) if sys.argv[1] == "online": + from ledgerblue.comm import getDongle get_online_seed(retrieve_language(True)) elif sys.argv[1] == "offline": get_offline_seed(retrieve_language(False))