From d95e0d9dda4cb0bdd9e761496c112ec26377031c Mon Sep 17 00:00:00 2001 From: Prince Anuragi Date: Thu, 26 May 2022 15:11:06 +0530 Subject: [PATCH 1/4] Address Generation is working, signing is stuck on io at the moment. --- run.sh | 10 +- src/archethic.c | 196 +++++++++++++++---- src/archethic.h | 14 +- src/getAddress.c | 42 ++-- src/getPublicKey.c | 14 +- src/signHash.c | 69 +++++-- tests/manual_testing/test.py | 13 +- tests/manual_testing/testcase_new.txt | 94 +++++++++ tests/manual_testing/wallet_encoder_new.ex | 215 +++++++++++++++++++++ 9 files changed, 585 insertions(+), 82 deletions(-) create mode 100644 tests/manual_testing/testcase_new.txt create mode 100644 tests/manual_testing/wallet_encoder_new.ex diff --git a/run.sh b/run.sh index b6d203a..4d48ee9 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,6 @@ #!/bin/bash -#make clean -#make -#../speculos/speculos.py --seed hex:9A34A233C48B77D48856ED171792D0B167F50D9A8148769E000D1F3C75F74C15 bin/app.elf -../speculos/speculos.py --seed hex:6fa774718b0f086101e7a0bf43f81944f2eea0392bc3452ac314cc444f19978989c62be4110f8fd3e543875e9f3fe2e2240f554cf16cfebf673b112ac44ec016 bin/app.elf -#../speculos/speculos.py bin/app.elf +make clean +make +# ../speculos/speculos.py --seed hex:9A34A233C48B77D48856ED171792D0B167F50D9A8148769E000D1F3C75F74C15 bin/app.elf +../speculos/speculos.py --seed hex:6fa774718b0f086101e7a0bf43f81944f2eea0392bc3452ac314cc444f19978989c62be4110f8fd3e543875e9f3fe2e2240f554cf16cfebf673b112ac44ec016 --color JADE_GREEN bin/app.elf +# ../speculos/speculos.py bin/app.elf diff --git a/src/archethic.c b/src/archethic.c index 8356c4b..d33923c 100644 --- a/src/archethic.c +++ b/src/archethic.c @@ -34,21 +34,40 @@ void getOriginPublicKey(cx_ecfp_public_key_t *publicKey) void performECDH(uint8_t *ephPublicKey, uint8_t ephPublicKeySize, uint8_t *ecdhPointX) { cx_ecfp_private_key_t originPrivateKey; + deriveArchEthicKeyPair(CX_CURVE_SECP256K1, 650, 0xffff, 0, NULL, 0, &originPrivateKey, NULL); + PRINTF("Private Key: \n %.*H \n", originPrivateKey.d_len, originPrivateKey.d); cx_ecdh(&originPrivateKey, CX_ECDH_X, ephPublicKey, ephPublicKeySize, ecdhPointX, 32); } void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffer, uint8_t dataLen, uint8_t *encodedWallet, uint8_t *walletLen) { + PRINTF("\n Recieved ECDH PointX: %.*H \n", ecdhPointLen, ecdhPointX); + uint8_t aes_key_iv_tag[64] = {0}; + + // Double Hashing sha512 Here using ecdhPointX cx_hash_sha512(ecdhPointX, ecdhPointLen, aes_key_iv_tag, sizeof(aes_key_iv_tag)); + cx_hash_sha512(aes_key_iv_tag, sizeof(aes_key_iv_tag), aes_key_iv_tag, sizeof(aes_key_iv_tag)); + PRINTF("\n AES Initial Vector: %.*H \n", sizeof(aes_key_iv_tag), aes_key_iv_tag); + uint8_t auth_key[32] = {0}; uint8_t auth_tag[32] = {0}; + // Auth Key is sha256 hash of last 16 bytes of aes_key_iv_tag cx_hash_sha256(aes_key_iv_tag + 48, 16, auth_key, sizeof(auth_key)); + + PRINTF("\n Auth Key: %.*H \n", sizeof(auth_key), auth_key); + + // Auth Tag is hmac_sha256 of dataBuffer cx_hmac_sha256(auth_key, sizeof(auth_key), dataBuffer + 16, 32, auth_tag, sizeof(auth_tag)); + + PRINTF("\n Auth Tag: %.*H \n", sizeof(auth_tag), auth_tag); + PRINTF("\n Buffer Tag: %.*H \n", 16, dataBuffer); + uint8_t verify_tag = memcmp(auth_tag, dataBuffer, 16); + // If verify tag is non zero then it's a bad decode. uint8_t wallet_key[32] = {0}; uint8_t wallet_iv[32] = {0}; @@ -66,6 +85,7 @@ void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffe // Encrypt == Decrypt in CTR mode, hence using CX_ENCRYPT for decrypt *walletLen = cx_aes_iv(&walletAESkey, CX_ENCRYPT | CX_CHAIN_CTR | CX_LAST | CX_PAD_NONE, wallet_iv, 16, dataBuffer + 16 + 32, dataLen - 16 - 32, encodedWallet, *walletLen); + PRINTF("\n Wallet Len Value, after decrypt: %d", *walletLen); } else { // BAD DECODE @@ -78,35 +98,121 @@ void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffe } } -void getBIP44Path(uint32_t address_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len) +void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len, uint32_t *seek_bytes) { - if (wallet_len < 5 * sequence_no + 39) + // Assuming minimum length for encoded onchain wallet be atleast 39 bytes + // Minimum bytes a service can have is 6 bytes + if (wallet_len < 6 * service_index + 39) return; - // strncpy(string_bip_44, "m/44'/650'/ffff'/0'/0'", 60); - int coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; - int account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; - strncpy(string_bip_44, "m/44'/", 7); - snprintf(string_bip_44 + 6, 6, "%d", coin_type); + // Read the encoded wallet in sequential manner here. + // Since paths and seed length can be varying + int seek_bytes_l = 0; + + // First 4 bytes are version of onchain wallet; + // encoded_wallet += 4 ; + seek_bytes_l += 4; + + // Read the seed length + uint8_t seed_length = encoded_wallet[seek_bytes_l]; + // encoded_wallet += 1; + seek_bytes_l += 1; + + PRINTF("\n Seed length Found to be : %d", seed_length); + // encoded_wallet += seed_length; + seek_bytes_l += seed_length; + + // Now encoded wallet is pointing to total no. of services + uint8_t total_services = encoded_wallet[seek_bytes_l]; + PRINTF("\n Total Serices found to be: %d \n", total_services); + // encoded_wallet += 1; + seek_bytes_l += 1; + + // Requesting Service Index cannot be outside of total services in onchain wallet + if (total_services < service_index) + return; + + int coin_type = 0; + int account = 0; + int address_index = 0; + + for (int c = 0; c <= service_index; c++) + { + // For each service seek and get the derivation path, if not the required service index seek to the next one; + if (c == service_index) + { + // Get the values and break + int name_len = encoded_wallet[seek_bytes_l]; + // encoded_wallet += name_len + 1; + seek_bytes_l += name_len + 1; + // int path_len = encoded_wallet [0]; + coin_type = (encoded_wallet[seek_bytes_l + 1] << 8) | encoded_wallet[seek_bytes_l + 2]; + account = (encoded_wallet[seek_bytes_l + 3] << 8) | encoded_wallet[seek_bytes_l + 4]; + address_index = (encoded_wallet[seek_bytes_l + 5] << 8) | encoded_wallet[seek_bytes_l + 6]; + break; + } + else + { + // Seek the encoded wallet to next service + int name_len = encoded_wallet[seek_bytes_l]; + // encoded_wallet += name_len + 1; + seek_bytes_l += name_len + 1; + int path_len = encoded_wallet[seek_bytes_l]; + // Extra two bytes are for curve type and hash type + // encoded_wallet += path_len + 1 + 1 + 1; + seek_bytes_l += path_len + 1 + 1 + 1; + } + } + + // int coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; + // int account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; + + PRINTF("\n Seek Bytes L: %d, \n", seek_bytes_l); + *seek_bytes = seek_bytes_l; + + PRINTF("\n Coin Type: %d \n", coin_type); + PRINTF("\n Account: %d \n", account); + PRINTF("\n Address Index: %d \n", address_index); + + strncpy(string_bip_44, "m/", 3); + snprintf(string_bip_44 + 2, 6, "%d", coin_type); strncpy(string_bip_44 + strlen(string_bip_44), "'/", 3); snprintf(string_bip_44 + strlen(string_bip_44), 6, "%d", account); - strncpy(string_bip_44 + strlen(string_bip_44), "'/0'/", 6); + strncpy(string_bip_44 + strlen(string_bip_44), "'/", 3); + snprintf(string_bip_44 + strlen(string_bip_44), 6, "%d", address_index); - format_u64(string_bip_44 + strlen(string_bip_44), 11, address_index); + // format_u64(string_bip_44 + strlen(string_bip_44), 11, address_index); strncpy(string_bip_44 + strlen(string_bip_44), "'", 2); + PRINTF("\n Final Derivation Path: %.*H \n ", sizeof(string_bip_44), string_bip_44); *bip44_len = strlen(string_bip_44); } -void generateKeyFromWallet(uint32_t address_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, uint8_t *curve_type, cx_ecfp_private_key_t *privateKey, cx_ecfp_public_key_t *publicKey) +void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t service_index, uint32_t seek_bytes, uint8_t *curve_type, cx_ecfp_private_key_t *privateKey, cx_ecfp_public_key_t *publicKey) { - if (*wallet_len < 5 * sequence_no + 39) + if (*wallet_len < 6 * service_index + 39) return; - uint32_t coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; - uint32_t account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; + + PRINTF("\n Seek Bytes Recieved: %d \n", seek_bytes); + + // Assuming Derivation Path to be 6 Bytes, 2 Bytes each coin_type | account | address_index + + uint32_t coin_type = (encoded_wallet[seek_bytes + 1] << 8) | encoded_wallet[seek_bytes + 2]; + uint32_t account = (encoded_wallet[seek_bytes + 3] << 8) | encoded_wallet[seek_bytes + 4]; + uint32_t address_index = (encoded_wallet[seek_bytes + 5] << 8) | encoded_wallet[seek_bytes + 6]; + + address_index += address_index_offset; + + PRINTF("\n Coin Type: %d \n", coin_type); + PRINTF("\n Account: %d \n", account); + PRINTF("\n Address Index: %d \n", address_index); + + // uint32_t coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; + // uint32_t account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; cx_curve_t curve; - *curve_type = encoded_wallet[5 * sequence_no + 38]; + *curve_type = encoded_wallet[seek_bytes + 7]; + PRINTF("\nCurve Type : %d\n", *curve_type); switch (*curve_type) { case 0: @@ -122,16 +228,20 @@ void generateKeyFromWallet(uint32_t address_index, uint8_t *encoded_wallet, uint curve = CX_CURVE_SECP256K1; break; } - deriveArchEthicKeyPair(curve, coin_type, account, address_index, encoded_wallet + 1, 32, privateKey, publicKey); + // First 4 bytes are version + uint8_t seed_len = encoded_wallet[4]; + PRINTF("\n Seed Length: %d \n", seed_len); + deriveArchEthicKeyPair(curve, coin_type, account, address_index, encoded_wallet + 5, seed_len, privateKey, publicKey); } -void generateArchEthicAddress(uint8_t hash_type, uint32_t address_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, uint8_t *address, uint8_t *address_len) +void generateArchEthicAddress(uint8_t hash_type, uint8_t service_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, uint8_t *address, uint8_t *address_len, uint32_t seek_bytes, uint32_t address_index_offset) { cx_ecfp_public_key_t publicKey; publicKey.W_len = 0; uint8_t curve_type = 255; - generateKeyFromWallet(address_index, encoded_wallet, wallet_len, sequence_no, &curve_type, NULL, &publicKey); + + generateKeyFromWallet(address_index_offset, encoded_wallet, wallet_len, service_index, seek_bytes, &curve_type, NULL, &publicKey); address[0] = curve_type; address[1] = 0; // onchain wallet origin @@ -153,7 +263,19 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou uint8_t rawPrivateKey[32]; cx_ecfp_private_key_t walletPrivateKey; - uint32_t bip44Path[] = {44 | 0x80000000, coin_type | 0x80000000, account | 0x80000000, 0x80000000, address_index | 0x80000000}; + // uint32_t bip44Path[] = {44 | 0x80000000, coin_type | 0x80000000, account | 0x80000000, 0x80000000, address_index | 0x80000000}; + + // New Scheme for derivation path is + // m/650'/0'/0' where m/coin_type(650' fixed for now)/account/address_index + uint32_t derivationPath[] = {coin_type | 0x80000000, + account | 0x80000000, + address_index | 0x80000000}; + + PRINTF("\n Derivation Path in Derive ARCH Keypair: %.*H \n", sizeof(derivationPath), derivationPath ); + PRINTF("\n Master Seed Supplied: %.*H \n", masterSeedLen, masterSeed); + + // If hashedPath is required, do it here + // Hashed Path is not required hence send raw paths. int mode = -1; if (curve == CX_CURVE_Ed25519) @@ -163,9 +285,9 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou if (account == 0xffff) // Derive the raw private key for the given path - os_perso_derive_node_with_seed_key(mode, curve, bip44Path, 5, rawPrivateKey, NULL, NULL, 0); + os_perso_derive_node_with_seed_key(mode, curve, derivationPath, 3, rawPrivateKey, NULL, NULL, 0); else - archethic_derive_node_with_seed_key(mode, curve, masterSeed, masterSeedLen, bip44Path, 5, rawPrivateKey, NULL, NULL, 0); + archethic_derive_node_with_seed_key(mode, curve, masterSeed, masterSeedLen, derivationPath, 3, rawPrivateKey, NULL, NULL, 0); // Initiate the private key structure with the raw private key cx_ecfp_init_private_key(curve, rawPrivateKey, 32, &walletPrivateKey); @@ -184,14 +306,18 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou explicit_bzero(&walletPrivateKey, sizeof(walletPrivateKey)); } -void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t sequence_no, uint8_t *asn_sign, uint8_t *sign_len) +void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index_offset, uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t service_index, uint32_t seek_bytes, uint8_t *asn_sign, uint8_t *sign_len) { uint8_t curve_type = 255; cx_ecfp_private_key_t privateKey; cx_ecfp_public_key_t publicKey; publicKey.W_len = 0; unsigned int info = 0; - generateKeyFromWallet(address_index, encoded_wallet, wallet_len, sequence_no, &curve_type, &privateKey, &publicKey); + + generateKeyFromWallet(address_index_offset, encoded_wallet, wallet_len, service_index, seek_bytes, &curve_type, &privateKey, &publicKey); + + PRINTF("\n Private Key Derived: %.*H \n", privateKey.d_len, privateKey.d); + PRINTF("\n Public Key Derived: %.*H \n", publicKey.W_len, publicKey.W); asn_sign[0] = curve_type; asn_sign[1] = 0; // Onchain Wallet Key @@ -227,8 +353,8 @@ void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, * After V1 Specs are implemented, remove * +1 from senderAddr and -1 from senderAddrLen */ - memcpy(tx + index, senderAddr + 1, senderAddrLen - 1); - index += senderAddrLen - 1; + memcpy(tx + index, senderAddr, senderAddrLen); + index += senderAddrLen; memcpy(tx + index, &tx_type, 1); index += 1; @@ -251,8 +377,8 @@ void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, * After V1 Specs are implemented, remove * +1 from receiveAddr and -1 from receiveAddrLen */ - memcpy(tx + index, receiveAddr + 1, receiveAddrLen - 1); - index += receiveAddrLen - 1; + memcpy(tx + index, receiveAddr, receiveAddrLen); + index += receiveAddrLen; memcpy(tx + index, amount, 8); index += 8; @@ -265,13 +391,15 @@ void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, *txHashLen = 32; cx_hash_sha256(tx, index, txHash, *txHashLen); + + PRINTF("\n Encoded Txn: ---------- \n"); + for (int k = 0; k < index; k++) + PRINTF("%02X", tx[k]); + PRINTF("\n\n"); + /* - for (int k = 0; k < index; k++) - PRINTF("%02X", tx[k]); - PRINTF("\n\n"); - - for (int k = 0; k < *txHashLen; k++) - PRINTF("%02X", txHash[k]); - PRINTF("\n\n"); - */ + for (int k = 0; k < *txHashLen; k++) + PRINTF("%02X", txHash[k]); + PRINTF("\n\n"); + */ } \ No newline at end of file diff --git a/src/archethic.h b/src/archethic.h index e2e627d..2d3b2e6 100644 --- a/src/archethic.h +++ b/src/archethic.h @@ -50,6 +50,8 @@ typedef struct uint8_t senderAddr[70]; uint8_t senderAddrLen; uint32_t address_index; + uint8_t service_index; + uint32_t seek_bytes; } tx_struct_t; void io_exchange_with_code(uint16_t code, uint16_t tx); @@ -62,22 +64,22 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou void performECDH(uint8_t *ephPublicKey, uint8_t ephPublicKeySize, uint8_t *ecdhPointX); -void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index, - uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t sequence_no, +void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index_offset, + uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t service_index, uint32_t seek_bytes, uint8_t *asn_sign, uint8_t *sign_len); void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffer, uint8_t dataLen, uint8_t *encodedWallet, uint8_t *walletLen); -void generateKeyFromWallet(uint32_t address_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, +void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t service_index, uint32_t seek_bytes, uint8_t *curve_type, cx_ecfp_private_key_t *privateKey, cx_ecfp_public_key_t *publicKey); -void generateArchEthicAddress(uint8_t hash_type, uint32_t address_index, +void generateArchEthicAddress(uint8_t hash_type, uint8_t service_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, - uint8_t *address, uint8_t *address_len); + uint8_t *address, uint8_t *address_len, uint32_t seek_bytes, uint32_t address_index_offset); -void getBIP44Path(uint32_t address_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len); +void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len, uint32_t *seek_bytes); void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, uint8_t *receiveAddr, uint8_t receiveAddrLen, diff --git a/src/getAddress.c b/src/getAddress.c index 953ffbc..1281126 100644 --- a/src/getAddress.c +++ b/src/getAddress.c @@ -20,7 +20,7 @@ static action_validate_cb g_validate_addr_callback; -static char g_bip44_path[40]; +static char g_derivation_path[30]; static char g_address[70]; static addr_struct_t g_addr; @@ -36,8 +36,8 @@ UX_STEP_NOCB(ux_display_confirm_address, bnnn_paging, { UX_STEP_NOCB(ux_display_addr_bip44, bnnn_paging, { - .title = "bip44 Path", - .text = g_bip44_path, + .title = "Derivation Path", + .text = g_derivation_path, }); // Step with title/text for public key @@ -99,21 +99,34 @@ void ui_validate_address_arch(bool choice) void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags) { // convert address index (big endian) - uint32_t address_index = 0; - for (int c = 0; c < 4; c++) - address_index |= (uint32_t)dataBuffer[c] << 8 * (3 - c); + // uint32_t address_index = 0; + // for (int c = 0; c < 4; c++) + // address_index |= (uint32_t)dataBuffer[c] << 8 * (3 - c); - dataBuffer += 4; - dataLength -= 4; + // dataBuffer += 4; + // dataLength -= 4; + + uint8_t service_index = 0; + service_index = dataBuffer[0]; + + dataBuffer += 1; + dataLength -= 1; + + // PRINTF("Address : \n %d \n", address_index); + PRINTF("Service Index : \n %d \n", service_index); uint8_t ecdhPointX[32] = {0}; performECDH(dataBuffer, 65, ecdhPointX); dataBuffer += 65; dataLength -= 65; + PRINTF("Point X Buffer: \n %.*H \n", 32, ecdhPointX); + // decrypt wallet g_wallet.walletLen = sizeof(g_wallet.encodedWallet); + decryptWallet(ecdhPointX, sizeof(ecdhPointX), dataBuffer, dataLength, g_wallet.encodedWallet, &g_wallet.walletLen); + if (g_wallet.walletLen == 5) { // return "BADDECODE" if authentication for wallet decryption failed memcpy(G_io_apdu_buffer, g_wallet.encodedWallet, g_wallet.walletLen); @@ -123,11 +136,18 @@ void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t data else *flags |= IO_ASYNCH_REPLY; + // If this is reached then we will have our encoded wallet + PRINTF("\n Encoded Wallet: %.*H \n ", g_wallet.walletLen, g_wallet.encodedWallet); + uint8_t bip44pathlen; - memset(g_bip44_path, 0, sizeof(g_bip44_path)); - getBIP44Path(address_index, g_wallet.encodedWallet, g_wallet.walletLen, 0, g_bip44_path, &bip44pathlen); + memset(g_derivation_path, 0, sizeof(g_derivation_path)); + uint32_t seek_bytes = 0; + getDerivationPath(service_index, g_wallet.encodedWallet, g_wallet.walletLen, 0, g_derivation_path, &bip44pathlen, &seek_bytes); + + PRINTF("\n Derivation Path from Main fn.: %.*H \n", sizeof(g_derivation_path), g_derivation_path); + PRINTF("\n Seek Bytes: %d \n", seek_bytes); - generateArchEthicAddress(0, address_index, g_wallet.encodedWallet, &g_wallet.walletLen, 0, g_addr.arch_address, &g_addr.arch_addr_len); + generateArchEthicAddress(0, service_index, g_wallet.encodedWallet, &g_wallet.walletLen, 0, g_addr.arch_address, &g_addr.arch_addr_len, seek_bytes, 0); memset(g_address, 0, sizeof(g_address)); snprintf(g_address, sizeof(g_address), "%.*H", sizeof(g_addr.arch_address), g_addr.arch_address); diff --git a/src/getPublicKey.c b/src/getPublicKey.c index 7969e92..855fb45 100644 --- a/src/getPublicKey.c +++ b/src/getPublicKey.c @@ -21,7 +21,8 @@ static action_validate_cb g_validate_callback; static char g_public_key[135]; // 1 + 4 + 130 -static char g_bip44_path[60]; +static char g_derivation_path[30]; +// Global Structure cx_ecfp_public_key_t publicKey; // Step with icon and text @@ -34,8 +35,8 @@ UX_STEP_NOCB(ux_display_confirm_addr_step, bnnn_paging, { UX_STEP_NOCB(ux_display_path_step, bnnn_paging, { - .title = "bip44 Path", - .text = g_bip44_path, + .title = "Derivation Path", + .text = g_derivation_path, }); // Step with title/text for public key @@ -101,14 +102,15 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t da { *flags |= IO_ASYNCH_REPLY; - memset(g_bip44_path, 0, sizeof(g_bip44_path)); + memset(g_derivation_path, 0, sizeof(g_derivation_path)); memset(g_public_key, 0, sizeof(g_public_key)); getOriginPublicKey(&publicKey); + // Append 0204 in front as per origin public key encoding snprintf(g_public_key, sizeof(g_public_key), "0204%.*H", publicKey.W_len, publicKey.W); - // g_bip44_path = "m/44'/650'/ffff'/0'/0'" always - strncpy(g_bip44_path, "m/44'/650'/ffff'/0'/0'", 60); + // g_derivation_path = "m/650'/ffff'/0'" always + strncpy(g_derivation_path, "m/650'/ffff'/0'", 30); g_validate_callback = &ui_action_validate_pubkey; ux_flow_init(0, ux_display_pubkey_flow, NULL); diff --git a/src/signHash.c b/src/signHash.c index b23c1e2..dfed36d 100644 --- a/src/signHash.c +++ b/src/signHash.c @@ -53,7 +53,7 @@ UX_STEP_NOCB(ux_display_txn_amount, UX_STEP_NOCB(ux_display_hash_addr_bip44, bnnn_paging, { - .title = "Signing BIP44 Path", + .title = "Sig w/ Derivation Path", .text = g_bip44_path, }); @@ -98,14 +98,27 @@ void ui_validate_sign_hash(bool choice) * signing key => address index * returns the Public Key + ASN SIGN */ - performECDSA(g_tx.txHash, g_tx.txHashLen, g_tx.address_index, - g_Wallet.encodedWallet, &g_Wallet.walletLen, 0, - g_Wallet.encodedWallet, &g_Wallet.walletLen); - + PRINTF("\n Transaction Hash: %.*H \n", g_tx.txHashLen, g_tx.txHash); + PRINTF("\n Signing Address Index: %d\n", g_tx.address_index); + PRINTF("\n Encoded Wallet Length: %d \n", g_Wallet.walletLen); + PRINTF("\n Encoded Wallet: %.*H", g_Wallet.walletLen, g_Wallet.encodedWallet); + performECDSA(g_tx.txHash, g_tx.txHashLen, 0, + g_Wallet.encodedWallet, &g_Wallet.walletLen, g_tx.service_index, + g_tx.seek_bytes, g_Wallet.encodedWallet, &g_Wallet.walletLen); + + PRINTF("\n Logic Has Exec. perform ECDSA. \n"); + PRINTF("\n Signature: %.*H \n", g_Wallet.walletLen, g_Wallet.encodedWallet); + PRINTF("\n Sig Len: %d \n", g_Wallet.walletLen); + PRINTF("\n Txn hash Len: %d \n", g_tx.txHashLen); + PRINTF("\n Total Len: %d \n", g_tx.txHashLen + g_Wallet.walletLen); + memcpy(G_io_apdu_buffer, g_tx.txHash, g_tx.txHashLen); memcpy(G_io_apdu_buffer + g_tx.txHashLen, g_Wallet.encodedWallet, g_Wallet.walletLen); - io_exchange_with_code(SW_OK, g_tx.txHashLen + g_Wallet.walletLen); + // Checking Contents of G_io_apdu_buffer + PRINTF("\n G_io_buf: %.*H \n", g_tx.txHashLen + g_Wallet.walletLen , G_io_apdu_buffer); + + io_exchange_with_code(SW_OK, 98); } else { @@ -115,15 +128,21 @@ void ui_validate_sign_hash(bool choice) ui_menu_main(); } +// data buffer is encoded as -> service_index + receiver + amount + enc_key + enc_wallet void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags) { // convert address index (big endian) - uint32_t address_index = 0; - for (int c = 0; c < 4; c++) - address_index |= (uint32_t)dataBuffer[c] << 8 * (3 - c); - g_tx.address_index = address_index; - dataBuffer += 4; - dataLength -= 4; + // uint32_t address_index = 0; + // for (int c = 0; c < 4; c++) + // address_index |= (uint32_t)dataBuffer[c] << 8 * (3 - c); + // g_tx.address_index = address_index; + // dataBuffer += 4; + // dataLength -= 4; + + uint8_t service_index = dataBuffer[0]; + g_tx.service_index = service_index; + dataBuffer += 1; + dataLength -= 1; // receiver address uint8_t addrLen = 0; @@ -151,7 +170,9 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe dispAmt |= (uint64_t)dataBuffer[c] << 8 * (7 - c); char test_g[30] = {0}; + format_fpu64(test_g, sizeof(test_g), dispAmt, 8); + memset(g_amount, 0, sizeof(g_amount)); memcpy(g_amount, test_g, 30); dataBuffer += 8; @@ -174,13 +195,27 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe else *flags |= IO_ASYNCH_REPLY; - // get sender address using address index + 1, according to specs V1 - generateArchEthicAddress(0, address_index + 1, g_Wallet.encodedWallet, &g_Wallet.walletLen, 0, g_tx.senderAddr, &g_tx.senderAddrLen); + // Wallet Successfully Decrypted Here. - // get BIP path for display + uint32_t seek_bytes = 0; + // get derivation path for display and seek bytes for current service uint8_t bip44pathlen; memset(g_bip44_path, 0, sizeof(g_bip44_path)); - getBIP44Path(address_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_bip44_path, &bip44pathlen); + getDerivationPath(service_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_bip44_path, &bip44pathlen, &seek_bytes); + + // get sender address using address index + 1, according to specs V1 + + PRINTF("\n Seek Bytes for current Service Index: %d \n", seek_bytes); + g_tx.seek_bytes = seek_bytes; + + uint32_t address_index = (g_Wallet.encodedWallet[seek_bytes + 5] << 8) | g_Wallet.encodedWallet[seek_bytes + 6]; + g_tx.address_index = address_index; + + // Offset address_index by +1 + + generateArchEthicAddress(0, service_index, g_Wallet.encodedWallet, &g_Wallet.walletLen, 0, g_tx.senderAddr, &g_tx.senderAddrLen, seek_bytes, 1); + + PRINTF("\n Sender Address: %.*H", g_tx.senderAddrLen, g_tx.senderAddr); // create transaction and get its hash (sha256) getTransactionHash(g_tx.senderAddr, g_tx.senderAddrLen, g_tx.receiveAddr, g_tx.receiveAddrLen, g_tx.amount, g_tx.txHash, &g_tx.txHashLen); @@ -189,6 +224,6 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe // set gui triggers g_validate_hash_callback = &ui_validate_sign_hash; - g_Wallet.walletLen = sizeof(g_Wallet.encodedWallet); + ux_flow_init(0, ux_display_sign_hash_main, NULL); } diff --git a/tests/manual_testing/test.py b/tests/manual_testing/test.py index 80200a8..da59e4d 100644 --- a/tests/manual_testing/test.py +++ b/tests/manual_testing/test.py @@ -20,16 +20,23 @@ transport = Transport(interface="tcp", server="127.0.0.1", port=9999, debug=True) -encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" +encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" +encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" + +# encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" +encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet address_index = "00000000" +service_index = "00" receiver = "020019CA33A6CA9E69B5C29E6E8497CC5AC9675952F847347709AD39C92C1B1B5313" amount = "000000038407B700" # Address APDU -#apdu_hex_payload = address_index + encrypted_key_plus_wallet +# apdu_hex_payload = address_index + encrypted_key_plus_wallet +# apdu_hex_payload = service_index + encrypted_key_plus_wallet # Sign APDU -apdu_hex_payload = address_index + receiver + amount + encrypted_key_plus_wallet +# apdu_hex_payload = address_index + receiver + amount + encrypted_key_plus_wallet +apdu_hex_payload = service_index + receiver + amount + encrypted_key_plus_wallet apdu_payload = bytes.fromhex(apdu_hex_payload) sw, response = transport.exchange( diff --git a/tests/manual_testing/testcase_new.txt b/tests/manual_testing/testcase_new.txt new file mode 100644 index 0000000..9b4877e --- /dev/null +++ b/tests/manual_testing/testcase_new.txt @@ -0,0 +1,94 @@ + +---------------------------------------------------- + + Master Seed Length: +20 + +Master Seed for Onchain Wallet (32 bytes) +6101EA75C066DE8D252100786CD22E0B11532915E855990DE6F359B7DBA4BC91 + + No. of services: +01 + + Service Name Length: +03 + + Service Name: +75636F + + Derivation Path Length: +06 + + Derivation Path (6 bytes): [Coin type = 650, account = 0, index = 0] +028A00000000 + +Wallet Curve (0:ed25519, 1:nistp256, 2:secp256k1): +02 + + Hash Type: 0: SHA256 (sha2) +1: SHA512 (sha2) +2: SHA3_256 (keccak) +3: SHA3_512 (keccak) +4: BLAKE2B +00 + +Encoded Wallet (version,master seed len, master seed, number of services, service name len, service name, derivation path len, derivcation path, wallet curve, hash type): +00000001206101EA75C066DE8D252100786CD22E0B11532915E855990DE6F359B7DBA4BC91010375636F06028A000000000200 + +---------------------------------------------------- + +Wallet Key (AES256 CTR) for encrypting Onchain Wallet (32 bytes) +477EF7476F0C8402361D57757A3E6F5B0C36EF804E48300128F4031D88A37C29 + +IV encrypting Onchain Wallet (SHA256(SHA256(Wallet Key)))[0:16] +2C36D83B3F6E910E0753EDD8E74BBB59 + +Encryption of Encoded Wallet (AES256 CTR): +098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D + +---------------------------------------------------- + +ECDH Curve (0:ed25519, 1:nistp256, 2:secp256k1): +02 + +Ephemeral Public Key +041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E98 + +Origin Device Public Key +0456ADC116763F07B1CDC6EC8E2453FCB5F67DDD96123C0B4955D7BF82EAB20FF190F871F3C514D2E81391C7FF314F0F18D38899EC43A7085ABE2BD90B0D147F30 + +ECDH Point x: ECDH(Origin Device Public Key, Ephemeral Private Key) +E6C4A1759DF6C1090F6253CD096D5F66627E62BE7322C5EC580925F38D18E95D + +---------------------------------------------------- + +AES256 CBC Key: SHA512(SHA512(ECDH Point x))[0:32] +E15A84B6E697FF0F11BF44BF3168E33BFDC48FD0CAD40F38CCFB073373F02CB7 + +IV: SHA512(SHA512(ECDH Point x))[32:48] +43FB4D6C24E8A930EF06C7B386A234FA + +Encryption of Wallet Key (AES256 CBC): +790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75 + +---------------------------------------------------- + +Authentication Seed: SHA512(SHA512(ECDH Point x))[48:64] +13AF1023BC0714185903058A13C506EF + +Authentication Key: SHA256(Authentication Seed) +42A184D308BE416889556F3D2C115842D1A68AA87E06F0E9B4A789CB52EBC8C6 + +Authentication Tag: HMAC256(Authentication Key, Encrypted Wallet Key)[0:16] +8BFA38917BF72DDBBB0A72E4EE839024 + +---------------------------------------------------- + +Encoding of Encrypted Wallet Key(ephemeral public key, authentication tag, encrypted wallet key): +041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75 + +---------------------------------------------------- +Interactive Elixir (1.13.3) - press Ctrl+C to exit (type h() ENTER for help) +iex(1)> +BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo + (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution diff --git a/tests/manual_testing/wallet_encoder_new.ex b/tests/manual_testing/wallet_encoder_new.ex new file mode 100644 index 0000000..7087ee0 --- /dev/null +++ b/tests/manual_testing/wallet_encoder_new.ex @@ -0,0 +1,215 @@ +# ******************************************************************************* +# Archethic Ledger Bolos App +# (c) 2022 Varun Deshpande, Uniris +# +# Licensed under the GNU Affero General Public License, Version 3 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.gnu.org/licenses/agpl-3.0.en.html +# +# 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. +# ******************************************************************************* + +# Archethic Onchain Wallet Generator and Encoder, using V1 specifications from https://hackmd.io/@219_ne6IRI6utatg6Fc8ZA/B1g0TU0uK + +# origin_public_key = "04523f9d4068555b8c30bd03507f8c4e454a399b39885555dba91477b3640047cbfb8201d11567faa7956b41bb4b7f207a0fd1641d77f32f53ed9f38b7ecff12fb" +# Ledger Origin Public Key with seed: 6fa774718b0f086101e7a0bf43f81944f2eea0392bc3452ac314cc444f19978989c62be4110f8fd3e543875e9f3fe2e2240f554cf16cfebf673b112ac44ec016 +origin_public_key = + "0456adc116763f07b1cdc6ec8e2453fcb5f67ddd96123c0b4955d7bf82eab20ff190f871f3c514d2e81391c7ff314f0f18d38899ec43a7085abe2bd90b0d147f30" + +{_ok, ledger} = Base.decode16(origin_public_key, case: :lower) + +# Version is 4 Bytes +{_ok, version} = Base.decode16("00000001") + +master_seed = :crypto.strong_rand_bytes(32) + +# {_ok, master_seed_length} = +# master_seed |> :erlang.byte_size() |> Integer.to_string() |> Base.encode16(case: :upper) + +{_ok, master_seed_length } = Base.decode16("20") + +{_ok, total_services} = Base.decode16("01") + +{_ok, service_name_length} = Base.decode16("03") + +# Convert String to Hex? +service_name = "uco" +# {_ok, service_name} = Base.encode16("uco", case: :upper ) + +{_ok, derivation_path_length} = Base.decode16("06") + +{_ok, coin_type} = Base.decode16("028A") +{_ok, account} = Base.decode16("0000") +{_ok, address_index} = Base.decode16("0000") +derivation_path = coin_type <> account <> address_index +{_ok, wallet_curve} = Base.decode16("02") +{_ok, hash_type} = Base.decode16("00") + +{_ok, ecdh_curve} = Base.decode16("02") +curve = :secp256k1 + +IO.puts("\n----------------------------------------------------") + +IO.puts("\n Master Seed Length: ") +IO.puts(Base.encode16(master_seed_length)) + +IO.puts("\nMaster Seed for Onchain Wallet (32 bytes)") +IO.puts(Base.encode16(master_seed)) + +IO.puts("\n No. of services: ") +IO.puts(Base.encode16(total_services)) + +IO.puts("\n Service Name Length: ") +IO.puts(Base.encode16(service_name_length)) + +IO.puts("\n Service Name: ") +IO.puts(Base.encode16(service_name)) + +IO.puts("\n Derivation Path Length: ") +IO.puts(Base.encode16(derivation_path_length)) + +IO.puts("\n Derivation Path (6 bytes): [Coin type = 650, account = 0, index = 0]") +IO.puts(Base.encode16(derivation_path)) + +IO.puts("\nWallet Curve (0:ed25519, 1:nistp256, 2:secp256k1): ") +IO.puts(Base.encode16(wallet_curve)) + +IO.puts("\n Hash Type: 0: SHA256 (sha2) +1: SHA512 (sha2) +2: SHA3_256 (keccak) +3: SHA3_512 (keccak) +4: BLAKE2B") +IO.puts(Base.encode16(hash_type)) + +# Encoded Wallet Scheme +# Version ,Seed size ,Seed ,Nb services ,Service name size ,Service name ,Derivation path length ,Derivation path ,Curve type ,Hash type ... +# 4 bytes 1 byte N bytes 1 byte 1 byte N bytes 1 byte N bytes 1 byte 1 byte ... + +encoded_wallet = + version <> + master_seed_length <> + master_seed <> + total_services <> + service_name_length <> + service_name <> derivation_path_length <> derivation_path <> wallet_curve <> hash_type + +IO.puts( + "\nEncoded Wallet (version,master seed len, master seed, number of services, service name len, service name, derivation path len, derivcation path, wallet curve, hash type):" +) + +IO.puts(Base.encode16(encoded_wallet)) + +IO.puts("\n----------------------------------------------------") + +wallet_encryption_key = :crypto.strong_rand_bytes(32) +IO.puts("\nWallet Key (AES256 CTR) for encrypting Onchain Wallet (32 bytes)") +IO.puts(Base.encode16(wallet_encryption_key)) + +<> = + :crypto.hash(:sha256, :crypto.hash(:sha256, wallet_encryption_key)) + +IO.puts("\nIV encrypting Onchain Wallet (SHA256(SHA256(Wallet Key)))[0:16]") +IO.puts(Base.encode16(wallet_encryption_iv)) + +encrypted_wallet = + :crypto.crypto_one_time( + :aes_256_ctr, + wallet_encryption_key, + wallet_encryption_iv, + encoded_wallet, + true + ) + +IO.puts("\nEncryption of Encoded Wallet (AES256 CTR):") +IO.puts(Base.encode16(encrypted_wallet)) + +IO.puts("\n----------------------------------------------------") + +IO.puts("\nECDH Curve (0:ed25519, 1:nistp256, 2:secp256k1): ") +IO.puts(Base.encode16(ecdh_curve)) + +IO.puts("\nEphemeral Public Key") +{ephemeral_pubkey, ephemeral_privkey} = :crypto.generate_key(:ecdh, curve) +IO.puts(Base.encode16(ephemeral_pubkey)) + +IO.puts("\nOrigin Device Public Key") +IO.puts(Base.encode16(ledger)) + +ecdh = :crypto.compute_key(:ecdh, ledger, ephemeral_privkey, curve) +IO.puts("\nECDH Point x: ECDH(Origin Device Public Key, Ephemeral Private Key)") +IO.puts(Base.encode16(ecdh)) + +IO.puts("\n----------------------------------------------------") + +<> = + :crypto.hash(:sha512, :crypto.hash(:sha512, ecdh)) + +IO.puts("\nAES256 CBC Key: SHA512(SHA512(ECDH Point x))[0:32]") +IO.puts(Base.encode16(aes_key)) + +IO.puts("\nIV: SHA512(SHA512(ECDH Point x))[32:48]") +IO.puts(Base.encode16(iv)) + +encrypted_wallet_key = + :crypto.crypto_one_time(:aes_256_cbc, aes_key, iv, wallet_encryption_key, true) + +IO.puts("\nEncryption of Wallet Key (AES256 CBC):") +IO.puts(Base.encode16(encrypted_wallet_key)) + +IO.puts("\n----------------------------------------------------") + +IO.puts("\nAuthentication Seed: SHA512(SHA512(ECDH Point x))[48:64]") +IO.puts(Base.encode16(auth_seed)) + +auth_key = :crypto.hash(:sha256, auth_seed) +IO.puts("\nAuthentication Key: SHA256(Authentication Seed)") +IO.puts(Base.encode16(auth_key)) + +<> = + :crypto.mac(:hmac, :sha256, auth_key, encrypted_wallet_key) + +IO.puts("\nAuthentication Tag: HMAC256(Authentication Key, Encrypted Wallet Key)[0:16]") +IO.puts(Base.encode16(auth_tag)) + +IO.puts("\n----------------------------------------------------") + +encoded_wallet_key = ephemeral_pubkey <> auth_tag <> encrypted_wallet_key + +IO.puts( + "\nEncoding of Encrypted Wallet Key(ephemeral public key, authentication tag, encrypted wallet key):" +) + +IO.puts(Base.encode16(encoded_wallet_key)) + +IO.puts("\n----------------------------------------------------") + +""" +{_ok, address_header} = Base.decode16("E0040000") +payload = encoded_wallet_key <> encrypted_wallet +{_ok, lc} = Base.decode16(Integer.to_string(byte_size(payload), 16)) +address_apdu = address_header <> lc <> payload +IO.puts("\nAddress APDU:") +IO.puts(Base.encode16(address_apdu)) + +{_ok, sign_header} = Base.decode16("E0080000") +tx_hash = :crypto.hash(:sha256, "ARCHETHIC") +IO.puts("\nTx Hash:") +IO.puts(Base.encode16(tx_hash)) + +payload = tx_hash <> payload +{_ok, lc} = Base.decode16(Integer.to_string(byte_size(payload), 16)) +sign_apdu = sign_header <> lc <> payload +IO.puts("\nSign APDU:") +IO.puts(Base.encode16(sign_apdu)) + +# elixir verify +# public_key = Base.decode16!("", case: :lower) +# sign = Base.decode16!("", case: :lower) +# :crypto.verify(:ecdsa, :sha256, "archethic", sign, [public_key, :secp256k1]) +""" From a5230b44ee4a6c45ea21474e57546f94684cef45 Mon Sep 17 00:00:00 2001 From: Prince Anuragi Date: Fri, 27 May 2022 11:20:43 +0530 Subject: [PATCH 2/4] Removed debug prints, adjusted tests, fixed signature stuck issue. --- Makefile | 2 +- src/archethic.c | 55 +++++-------------- src/archethic.h | 4 +- src/getAddress.c | 11 +--- src/signHash.c | 42 +++++++------- tests/archethic_client/archethic_cmd.py | 14 +++-- .../archethic_client/archethic_cmd_builder.py | 16 +++--- tests/manual_testing/test.py | 2 +- tests/test_arch_addr.py | 15 +++-- tests/test_sign_hash.py | 11 ++-- 10 files changed, 75 insertions(+), 97 deletions(-) diff --git a/Makefile b/Makefile index 73dd613..5cf4a4b 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ APP_LOAD_PARAMS=--appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS else APP_LOAD_PARAMS=--appFlags 0x000 endif -APP_LOAD_PARAMS += --path "44'/650'" +APP_LOAD_PARAMS += --path "650'" APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS) APPNAME = "ARCHEthic" diff --git a/src/archethic.c b/src/archethic.c index d33923c..2097757 100644 --- a/src/archethic.c +++ b/src/archethic.c @@ -22,6 +22,7 @@ void io_exchange_with_code(uint16_t code, uint16_t tx) { G_io_apdu_buffer[tx++] = code >> 8; G_io_apdu_buffer[tx++] = code & 0xFF; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx); } @@ -36,13 +37,12 @@ void performECDH(uint8_t *ephPublicKey, uint8_t ephPublicKeySize, uint8_t *ecdhP cx_ecfp_private_key_t originPrivateKey; deriveArchEthicKeyPair(CX_CURVE_SECP256K1, 650, 0xffff, 0, NULL, 0, &originPrivateKey, NULL); - PRINTF("Private Key: \n %.*H \n", originPrivateKey.d_len, originPrivateKey.d); + cx_ecdh(&originPrivateKey, CX_ECDH_X, ephPublicKey, ephPublicKeySize, ecdhPointX, 32); } void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffer, uint8_t dataLen, uint8_t *encodedWallet, uint8_t *walletLen) { - PRINTF("\n Recieved ECDH PointX: %.*H \n", ecdhPointLen, ecdhPointX); uint8_t aes_key_iv_tag[64] = {0}; @@ -51,21 +51,14 @@ void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffe cx_hash_sha512(aes_key_iv_tag, sizeof(aes_key_iv_tag), aes_key_iv_tag, sizeof(aes_key_iv_tag)); - PRINTF("\n AES Initial Vector: %.*H \n", sizeof(aes_key_iv_tag), aes_key_iv_tag); - uint8_t auth_key[32] = {0}; uint8_t auth_tag[32] = {0}; // Auth Key is sha256 hash of last 16 bytes of aes_key_iv_tag cx_hash_sha256(aes_key_iv_tag + 48, 16, auth_key, sizeof(auth_key)); - PRINTF("\n Auth Key: %.*H \n", sizeof(auth_key), auth_key); - // Auth Tag is hmac_sha256 of dataBuffer cx_hmac_sha256(auth_key, sizeof(auth_key), dataBuffer + 16, 32, auth_tag, sizeof(auth_tag)); - PRINTF("\n Auth Tag: %.*H \n", sizeof(auth_tag), auth_tag); - PRINTF("\n Buffer Tag: %.*H \n", 16, dataBuffer); - uint8_t verify_tag = memcmp(auth_tag, dataBuffer, 16); // If verify tag is non zero then it's a bad decode. @@ -85,7 +78,6 @@ void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffe // Encrypt == Decrypt in CTR mode, hence using CX_ENCRYPT for decrypt *walletLen = cx_aes_iv(&walletAESkey, CX_ENCRYPT | CX_CHAIN_CTR | CX_LAST | CX_PAD_NONE, wallet_iv, 16, dataBuffer + 16 + 32, dataLen - 16 - 32, encodedWallet, *walletLen); - PRINTF("\n Wallet Len Value, after decrypt: %d", *walletLen); } else { // BAD DECODE @@ -110,22 +102,19 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w int seek_bytes_l = 0; // First 4 bytes are version of onchain wallet; - // encoded_wallet += 4 ; + seek_bytes_l += 4; // Read the seed length uint8_t seed_length = encoded_wallet[seek_bytes_l]; - // encoded_wallet += 1; + seek_bytes_l += 1; - PRINTF("\n Seed length Found to be : %d", seed_length); - // encoded_wallet += seed_length; seek_bytes_l += seed_length; // Now encoded wallet is pointing to total no. of services uint8_t total_services = encoded_wallet[seek_bytes_l]; - PRINTF("\n Total Serices found to be: %d \n", total_services); - // encoded_wallet += 1; + seek_bytes_l += 1; // Requesting Service Index cannot be outside of total services in onchain wallet @@ -167,13 +156,8 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w // int coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; // int account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; - PRINTF("\n Seek Bytes L: %d, \n", seek_bytes_l); *seek_bytes = seek_bytes_l; - PRINTF("\n Coin Type: %d \n", coin_type); - PRINTF("\n Account: %d \n", account); - PRINTF("\n Address Index: %d \n", address_index); - strncpy(string_bip_44, "m/", 3); snprintf(string_bip_44 + 2, 6, "%d", coin_type); @@ -184,7 +168,7 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w // format_u64(string_bip_44 + strlen(string_bip_44), 11, address_index); strncpy(string_bip_44 + strlen(string_bip_44), "'", 2); - PRINTF("\n Final Derivation Path: %.*H \n ", sizeof(string_bip_44), string_bip_44); + *bip44_len = strlen(string_bip_44); } @@ -193,8 +177,6 @@ void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_walle if (*wallet_len < 6 * service_index + 39) return; - PRINTF("\n Seek Bytes Recieved: %d \n", seek_bytes); - // Assuming Derivation Path to be 6 Bytes, 2 Bytes each coin_type | account | address_index uint32_t coin_type = (encoded_wallet[seek_bytes + 1] << 8) | encoded_wallet[seek_bytes + 2]; @@ -203,16 +185,11 @@ void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_walle address_index += address_index_offset; - PRINTF("\n Coin Type: %d \n", coin_type); - PRINTF("\n Account: %d \n", account); - PRINTF("\n Address Index: %d \n", address_index); - // uint32_t coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; // uint32_t account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; cx_curve_t curve; *curve_type = encoded_wallet[seek_bytes + 7]; - PRINTF("\nCurve Type : %d\n", *curve_type); switch (*curve_type) { case 0: @@ -230,7 +207,7 @@ void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_walle } // First 4 bytes are version uint8_t seed_len = encoded_wallet[4]; - PRINTF("\n Seed Length: %d \n", seed_len); + deriveArchEthicKeyPair(curve, coin_type, account, address_index, encoded_wallet + 5, seed_len, privateKey, publicKey); } @@ -271,9 +248,6 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou account | 0x80000000, address_index | 0x80000000}; - PRINTF("\n Derivation Path in Derive ARCH Keypair: %.*H \n", sizeof(derivationPath), derivationPath ); - PRINTF("\n Master Seed Supplied: %.*H \n", masterSeedLen, masterSeed); - // If hashedPath is required, do it here // Hashed Path is not required hence send raw paths. @@ -316,15 +290,14 @@ void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index_off generateKeyFromWallet(address_index_offset, encoded_wallet, wallet_len, service_index, seek_bytes, &curve_type, &privateKey, &publicKey); - PRINTF("\n Private Key Derived: %.*H \n", privateKey.d_len, privateKey.d); - PRINTF("\n Public Key Derived: %.*H \n", publicKey.W_len, publicKey.W); - asn_sign[0] = curve_type; asn_sign[1] = 0; // Onchain Wallet Key memcpy(asn_sign + 2, publicKey.W, publicKey.W_len); - *sign_len = cx_ecdsa_sign(&privateKey, CX_RND_TRNG, CX_SHA256, txHash, txHashLen, asn_sign + publicKey.W_len + 2, *sign_len - publicKey.W_len - 2, &info); + *sign_len = cx_ecdsa_sign(&privateKey, CX_RND_TRNG, CX_SHA256, txHash, txHashLen, asn_sign + publicKey.W_len + 2, MAX_ENCODE_WALLET_LEN - publicKey.W_len - 2, &info); *sign_len += publicKey.W_len + 2; + + } void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, @@ -392,10 +365,10 @@ void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, *txHashLen = 32; cx_hash_sha256(tx, index, txHash, *txHashLen); - PRINTF("\n Encoded Txn: ---------- \n"); - for (int k = 0; k < index; k++) - PRINTF("%02X", tx[k]); - PRINTF("\n\n"); + // PRINTF("\n Encoded Txn: ---------- \n"); + // for (int k = 0; k < index; k++) + // PRINTF("%02X", tx[k]); + // PRINTF("\n\n"); /* for (int k = 0; k < *txHashLen; k++) diff --git a/src/archethic.h b/src/archethic.h index 2d3b2e6..3e95d28 100644 --- a/src/archethic.h +++ b/src/archethic.h @@ -27,9 +27,11 @@ typedef void (*action_validate_cb)(bool); +#define MAX_ENCODE_WALLET_LEN 200 + typedef struct { - uint8_t encodedWallet[200]; + uint8_t encodedWallet[MAX_ENCODE_WALLET_LEN]; uint8_t walletLen; } onchain_wallet_struct_t; diff --git a/src/getAddress.c b/src/getAddress.c index 1281126..21739f7 100644 --- a/src/getAddress.c +++ b/src/getAddress.c @@ -112,16 +112,11 @@ void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t data dataBuffer += 1; dataLength -= 1; - // PRINTF("Address : \n %d \n", address_index); - PRINTF("Service Index : \n %d \n", service_index); - uint8_t ecdhPointX[32] = {0}; performECDH(dataBuffer, 65, ecdhPointX); dataBuffer += 65; dataLength -= 65; - PRINTF("Point X Buffer: \n %.*H \n", 32, ecdhPointX); - // decrypt wallet g_wallet.walletLen = sizeof(g_wallet.encodedWallet); @@ -137,16 +132,12 @@ void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t data *flags |= IO_ASYNCH_REPLY; // If this is reached then we will have our encoded wallet - PRINTF("\n Encoded Wallet: %.*H \n ", g_wallet.walletLen, g_wallet.encodedWallet); - + uint8_t bip44pathlen; memset(g_derivation_path, 0, sizeof(g_derivation_path)); uint32_t seek_bytes = 0; getDerivationPath(service_index, g_wallet.encodedWallet, g_wallet.walletLen, 0, g_derivation_path, &bip44pathlen, &seek_bytes); - PRINTF("\n Derivation Path from Main fn.: %.*H \n", sizeof(g_derivation_path), g_derivation_path); - PRINTF("\n Seek Bytes: %d \n", seek_bytes); - generateArchEthicAddress(0, service_index, g_wallet.encodedWallet, &g_wallet.walletLen, 0, g_addr.arch_address, &g_addr.arch_addr_len, seek_bytes, 0); memset(g_address, 0, sizeof(g_address)); snprintf(g_address, sizeof(g_address), "%.*H", sizeof(g_addr.arch_address), g_addr.arch_address); diff --git a/src/signHash.c b/src/signHash.c index dfed36d..4a60476 100644 --- a/src/signHash.c +++ b/src/signHash.c @@ -21,9 +21,9 @@ static action_validate_cb g_validate_hash_callback; static char g_hash[67]; -static char g_addr[72]; +static char g_addr[70]; static char g_amount[30]; -static char g_bip44_path[40]; +static char g_derivation_path[34]; static tx_struct_t g_tx; static onchain_wallet_struct_t g_Wallet; @@ -54,7 +54,7 @@ UX_STEP_NOCB(ux_display_hash_addr_bip44, bnnn_paging, { .title = "Sig w/ Derivation Path", - .text = g_bip44_path, + .text = g_derivation_path, }); // Step with approve button @@ -98,30 +98,28 @@ void ui_validate_sign_hash(bool choice) * signing key => address index * returns the Public Key + ASN SIGN */ - PRINTF("\n Transaction Hash: %.*H \n", g_tx.txHashLen, g_tx.txHash); - PRINTF("\n Signing Address Index: %d\n", g_tx.address_index); - PRINTF("\n Encoded Wallet Length: %d \n", g_Wallet.walletLen); - PRINTF("\n Encoded Wallet: %.*H", g_Wallet.walletLen, g_Wallet.encodedWallet); + // PRINTF("\n Transaction Hash: %.*H \n", g_tx.txHashLen, g_tx.txHash); + // PRINTF("\n Signing Address Index: %d\n", g_tx.address_index); + // PRINTF("\n Encoded Wallet Length: %d \n", g_Wallet.walletLen); + // PRINTF("\n Encoded Wallet: %.*H", g_Wallet.walletLen, g_Wallet.encodedWallet); performECDSA(g_tx.txHash, g_tx.txHashLen, 0, g_Wallet.encodedWallet, &g_Wallet.walletLen, g_tx.service_index, g_tx.seek_bytes, g_Wallet.encodedWallet, &g_Wallet.walletLen); - PRINTF("\n Logic Has Exec. perform ECDSA. \n"); - PRINTF("\n Signature: %.*H \n", g_Wallet.walletLen, g_Wallet.encodedWallet); - PRINTF("\n Sig Len: %d \n", g_Wallet.walletLen); - PRINTF("\n Txn hash Len: %d \n", g_tx.txHashLen); - PRINTF("\n Total Len: %d \n", g_tx.txHashLen + g_Wallet.walletLen); - + // PRINTF("\n Signature: %.*H \n", g_Wallet.walletLen, g_Wallet.encodedWallet); + // PRINTF("\n Sig Len: %d \n", g_Wallet.walletLen); + // PRINTF("\n Txn hash Len: %d \n", g_tx.txHashLen); + // PRINTF("\n Total Len: %d \n", g_tx.txHashLen + g_Wallet.walletLen); + memcpy(G_io_apdu_buffer, g_tx.txHash, g_tx.txHashLen); memcpy(G_io_apdu_buffer + g_tx.txHashLen, g_Wallet.encodedWallet, g_Wallet.walletLen); - // Checking Contents of G_io_apdu_buffer - PRINTF("\n G_io_buf: %.*H \n", g_tx.txHashLen + g_Wallet.walletLen , G_io_apdu_buffer); - - io_exchange_with_code(SW_OK, 98); + io_exchange_with_code(SW_OK, g_tx.txHashLen + g_Wallet.walletLen); } else { + // Reset Buffer to all 0 + explicit_bzero(G_io_apdu_buffer, sizeof(G_io_apdu_buffer)); io_exchange_with_code(SW_USER_REJECTED, 0); } @@ -192,20 +190,19 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe io_exchange_with_code(SW_WRONG_WALLET, g_Wallet.walletLen); return; } - else - *flags |= IO_ASYNCH_REPLY; + // else + *flags |= IO_ASYNCH_REPLY; // Wallet Successfully Decrypted Here. uint32_t seek_bytes = 0; // get derivation path for display and seek bytes for current service uint8_t bip44pathlen; - memset(g_bip44_path, 0, sizeof(g_bip44_path)); - getDerivationPath(service_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_bip44_path, &bip44pathlen, &seek_bytes); + memset(g_derivation_path, 0, sizeof(g_derivation_path)); + getDerivationPath(service_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_derivation_path, &bip44pathlen, &seek_bytes); // get sender address using address index + 1, according to specs V1 - PRINTF("\n Seek Bytes for current Service Index: %d \n", seek_bytes); g_tx.seek_bytes = seek_bytes; uint32_t address_index = (g_Wallet.encodedWallet[seek_bytes + 5] << 8) | g_Wallet.encodedWallet[seek_bytes + 6]; @@ -215,7 +212,6 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe generateArchEthicAddress(0, service_index, g_Wallet.encodedWallet, &g_Wallet.walletLen, 0, g_tx.senderAddr, &g_tx.senderAddrLen, seek_bytes, 1); - PRINTF("\n Sender Address: %.*H", g_tx.senderAddrLen, g_tx.senderAddr); // create transaction and get its hash (sha256) getTransactionHash(g_tx.senderAddr, g_tx.senderAddrLen, g_tx.receiveAddr, g_tx.receiveAddrLen, g_tx.amount, g_tx.txHash, &g_tx.txHashLen); diff --git a/tests/archethic_client/archethic_cmd.py b/tests/archethic_client/archethic_cmd.py index ecccd01..b9312d7 100644 --- a/tests/archethic_client/archethic_cmd.py +++ b/tests/archethic_client/archethic_cmd.py @@ -110,9 +110,9 @@ def get_public_key(self, hid, display: bool = False) -> Tuple[hex, hex, hex, hex return curve_type, device_origin, path_form, x, y - def get_arch_addr(self, hid, enc_oc_wallet, addr_index, display: bool = False): + def get_arch_addr(self, hid, enc_oc_wallet, service_index, display: bool = False): self.transport.send_raw( - self.builder.get_arch_address(enc_oc_wallet, addr_index, display=display,) + self.builder.get_arch_address(enc_oc_wallet, service_index, display=display,) ) # type: int, bytes if (not hid): @@ -144,11 +144,11 @@ def get_arch_addr(self, hid, enc_oc_wallet, addr_index, display: bool = False): return curve_type, hash_type, hash_enc_pub_key - def sign_txn_hash(self, hid, enc_oc_wallet, addr_index, receiver_addr, amount, display: bool = False): + def sign_txn_hash(self, hid, enc_oc_wallet, service_index, receiver_addr, amount, display: bool = False): self.transport.send_raw( self.builder.sign_txn_hash_build( - enc_oc_wallet, addr_index, receiver_addr, amount, display) + enc_oc_wallet, service_index, receiver_addr, amount, display) ) # type: int, bytes if (not hid): @@ -170,8 +170,12 @@ def sign_txn_hash(self, hid, enc_oc_wallet, addr_index, receiver_addr, amount, d # APDU Response have following # Final Tx Hash (SHA256) || Corresponding public key from whose private key the signature was made || ASN DER Signature || + print("len res: ", len(response)) + offset = 0 final_txn_hash = response[offset: offset + 64] + print(final_txn_hash) + offset += 64 curve_type = response[offset: offset + 2] @@ -180,8 +184,10 @@ def sign_txn_hash(self, hid, enc_oc_wallet, addr_index, receiver_addr, amount, d # Check for the form 04 mean it is uncompressed assert(pubkey_tag == "04") public_key = response[offset:offset+67*2] + print(public_key) offset += 67*2 + print("Offset After Extracting PublicKey: ", offset) sign_tag: hex = response[offset: offset + 2] # Check if sign tag assert(sign_tag == "30") diff --git a/tests/archethic_client/archethic_cmd_builder.py b/tests/archethic_client/archethic_cmd_builder.py index fd55eb8..19e7336 100644 --- a/tests/archethic_client/archethic_cmd_builder.py +++ b/tests/archethic_client/archethic_cmd_builder.py @@ -148,7 +148,7 @@ def get_public_key(self, display: bool = False) -> bytes: p2=0x00, cdata=b"") - def get_arch_address(self, enc_oc_wallet, addr_index, display: bool = False): + def get_arch_address(self, enc_oc_wallet, service_index, display: bool = False): """Command builder for GET_ARCH_ADDR. Parameters @@ -157,8 +157,8 @@ def get_arch_address(self, enc_oc_wallet, addr_index, display: bool = False): Whether you want to display the address on the device. enc_oc_wallet: String The Encyrpted onchain wallet with key or in short encrypted key plus wallet - addr_index: string - The address index to which address need to be derived + service_index: string + The service index to which address need to be derived => each service has a derivation path which is defined in encoded wallet Returns ------- @@ -167,7 +167,7 @@ def get_arch_address(self, enc_oc_wallet, addr_index, display: bool = False): """ # As per specification https://hackmd.io/0fKm_XjJQuu46ph6zP5doQ#Get-ArchEthic-Account-Address - cdata: bytes = bytes.fromhex(addr_index + enc_oc_wallet) + cdata: bytes = bytes.fromhex(service_index + enc_oc_wallet) return self.serialize(cla=self.CLA, ins=InsType.INS_GET_ARCH_ADDR, @@ -175,15 +175,15 @@ def get_arch_address(self, enc_oc_wallet, addr_index, display: bool = False): p2=0x00, cdata=cdata) - def sign_txn_hash_build(self, enc_oc_wallet, addr_index, receiver_addr, amount, display: bool = False): + def sign_txn_hash_build(self, enc_oc_wallet, service_index, receiver_addr, amount, display: bool = False): """Command builder for SIGN_TX. Parameters ---------- enc_oc_wallet: String The Encyrpted onchain wallet with key or in short encrypted key plus wallet - addr_index: string - The address index to which address need to be derived + service_index: string + The service index to which derivation path's address need to be derived receiver_addr: string The receiver address which will receive the amount amount: string @@ -197,7 +197,7 @@ def sign_txn_hash_build(self, enc_oc_wallet, addr_index, receiver_addr, amount, APDU command for SIGN_TX. """ - cdata: bytes = bytes.fromhex(addr_index + receiver_addr + amount + enc_oc_wallet) + cdata: bytes = bytes.fromhex(service_index + receiver_addr + amount + enc_oc_wallet) return self.serialize(cla=self.CLA, ins=InsType.INS_SIGN_TX, diff --git a/tests/manual_testing/test.py b/tests/manual_testing/test.py index da59e4d..1e4facc 100644 --- a/tests/manual_testing/test.py +++ b/tests/manual_testing/test.py @@ -19,11 +19,11 @@ #transport = Transport(interface="hid", debug=True) transport = Transport(interface="tcp", server="127.0.0.1", port=9999, debug=True) +# encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" -# encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet address_index = "00000000" service_index = "00" diff --git a/tests/test_arch_addr.py b/tests/test_arch_addr.py index 545ae45..7e33f66 100644 --- a/tests/test_arch_addr.py +++ b/tests/test_arch_addr.py @@ -1,11 +1,18 @@ def test_get_arch_addr(cmd, hid): # Testing with a predefined onchain wallet - encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" - # Need First Address Index - address_index = "00000000" + + encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" + encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" - curve_type, hash_type, hash_enc_pub_key = cmd.get_arch_addr(hid, encrypted_key_plus_wallet, address_index) + encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet + + # Need the service index for whose derivation path needs to be used + service_index = "00" + + # APDU Command is => service_index (1byte) | encrypted_key | encrypted_wallet + + curve_type, hash_type, hash_enc_pub_key = cmd.get_arch_addr(hid, encrypted_key_plus_wallet, service_index) # curve_type => 0: ED25519, 1: NISTP256, 2: SECP256K1 # hash_type => 0 -> SHA256 (sha2) 1 -> SHA512 (sha2) 2 -> SHA3_256 (keccak) 3 -> SHA3_512 (keccak) 4 -> BLAKE2B diff --git a/tests/test_sign_hash.py b/tests/test_sign_hash.py index da01306..460400d 100644 --- a/tests/test_sign_hash.py +++ b/tests/test_sign_hash.py @@ -11,10 +11,13 @@ def test_sign_txn_hash(cmd, hid): # Testing with a predefined onchain wallet - encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" + encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" + encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" - # Address Index to perform signature - address_index = "00000000" + encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet + + # service index for which derivation path will be used to sign + service_index = "00" # Receiver Address as per specification receiver = "020019CA33A6CA9E69B5C29E6E8497CC5AC9675952F847347709AD39C92C1B1B5313" @@ -23,7 +26,7 @@ def test_sign_txn_hash(cmd, hid): amount = "000000038407B700" final_txn_hash, curve_type, origin_type, pubkey_tag, public_key, sign_tag, sign_len, asn_der_sign = cmd.sign_txn_hash( - hid, encrypted_key_plus_wallet, address_index, receiver, amount, hid) + hid, encrypted_key_plus_wallet, service_index, receiver, amount, hid) pubkeyPair = pubkey_pair(public_key) sign = sign_pair(asn_der_sign) From c82a3685cb6597a6fe048821cd7d6424de9bb072 Mon Sep 17 00:00:00 2001 From: Prince Anuragi Date: Fri, 27 May 2022 11:54:21 +0530 Subject: [PATCH 3/4] Tested with H/W Ledger Device Nano S --- tests/manual_testing/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual_testing/test.py b/tests/manual_testing/test.py index 1e4facc..f767f62 100644 --- a/tests/manual_testing/test.py +++ b/tests/manual_testing/test.py @@ -16,7 +16,7 @@ ********************************************************************************""" from ledgercomm import Transport # Nano S/X using HID interface -#transport = Transport(interface="hid", debug=True) +# transport = Transport(interface="hid", debug=True) transport = Transport(interface="tcp", server="127.0.0.1", port=9999, debug=True) # encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" From 6c415eb529a4529c31552f2707a5da34fa8a1d55 Mon Sep 17 00:00:00 2001 From: Prince Anuragi Date: Mon, 30 May 2022 15:34:10 +0530 Subject: [PATCH 4/4] Change of Derivation Path retrieval form encoded integer to raw hex encode string --- src/archethic.c | 113 ++++++++++++++------- src/archethic.h | 2 +- src/signHash.c | 17 +--- tests/manual_testing/test.py | 4 +- tests/manual_testing/testcase_new.txt | 38 ++++--- tests/manual_testing/wallet_encoder_new.ex | 20 ++-- tests/test_arch_addr.py | 4 +- tests/test_sign_hash.py | 4 +- 8 files changed, 117 insertions(+), 85 deletions(-) diff --git a/src/archethic.c b/src/archethic.c index 2097757..c01470a 100644 --- a/src/archethic.c +++ b/src/archethic.c @@ -90,7 +90,7 @@ void decryptWallet(uint8_t *ecdhPointX, uint8_t ecdhPointLen, uint8_t *dataBuffe } } -void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len, uint32_t *seek_bytes) +void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_derivation_path, uint8_t *derivation_path_len, uint32_t *seek_bytes) { // Assuming minimum length for encoded onchain wallet be atleast 39 bytes // Minimum bytes a service can have is 6 bytes @@ -114,17 +114,13 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w // Now encoded wallet is pointing to total no. of services uint8_t total_services = encoded_wallet[seek_bytes_l]; - + seek_bytes_l += 1; // Requesting Service Index cannot be outside of total services in onchain wallet if (total_services < service_index) return; - int coin_type = 0; - int account = 0; - int address_index = 0; - for (int c = 0; c <= service_index; c++) { // For each service seek and get the derivation path, if not the required service index seek to the next one; @@ -134,10 +130,14 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w int name_len = encoded_wallet[seek_bytes_l]; // encoded_wallet += name_len + 1; seek_bytes_l += name_len + 1; - // int path_len = encoded_wallet [0]; - coin_type = (encoded_wallet[seek_bytes_l + 1] << 8) | encoded_wallet[seek_bytes_l + 2]; - account = (encoded_wallet[seek_bytes_l + 3] << 8) | encoded_wallet[seek_bytes_l + 4]; - address_index = (encoded_wallet[seek_bytes_l + 5] << 8) | encoded_wallet[seek_bytes_l + 6]; + + int path_len = encoded_wallet[seek_bytes_l]; + + // Derivation Path is in the form m/650'/0'/0' + + // +1 in path len is required for null char in string + snprintf(string_derivation_path, path_len + 1, "%s", encoded_wallet + seek_bytes_l + 1); + *derivation_path_len = strlen(string_derivation_path); break; } else @@ -153,23 +153,7 @@ void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t w } } - // int coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; - // int account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; - *seek_bytes = seek_bytes_l; - - strncpy(string_bip_44, "m/", 3); - snprintf(string_bip_44 + 2, 6, "%d", coin_type); - - strncpy(string_bip_44 + strlen(string_bip_44), "'/", 3); - snprintf(string_bip_44 + strlen(string_bip_44), 6, "%d", account); - strncpy(string_bip_44 + strlen(string_bip_44), "'/", 3); - snprintf(string_bip_44 + strlen(string_bip_44), 6, "%d", address_index); - - // format_u64(string_bip_44 + strlen(string_bip_44), 11, address_index); - strncpy(string_bip_44 + strlen(string_bip_44), "'", 2); - - *bip44_len = strlen(string_bip_44); } void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_wallet, uint8_t *wallet_len, uint8_t service_index, uint32_t seek_bytes, uint8_t *curve_type, cx_ecfp_private_key_t *privateKey, cx_ecfp_public_key_t *publicKey) @@ -177,19 +161,74 @@ void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_walle if (*wallet_len < 6 * service_index + 39) return; - // Assuming Derivation Path to be 6 Bytes, 2 Bytes each coin_type | account | address_index + // Parse the Derivation Path into components here + int path_len = encoded_wallet[seek_bytes]; + + char temp_der_path[30]; + explicit_bzero(temp_der_path, sizeof(temp_der_path)); - uint32_t coin_type = (encoded_wallet[seek_bytes + 1] << 8) | encoded_wallet[seek_bytes + 2]; - uint32_t account = (encoded_wallet[seek_bytes + 3] << 8) | encoded_wallet[seek_bytes + 4]; - uint32_t address_index = (encoded_wallet[seek_bytes + 5] << 8) | encoded_wallet[seek_bytes + 6]; + snprintf(temp_der_path, path_len + 1, "%s", encoded_wallet + seek_bytes + 1); - address_index += address_index_offset; + // Derivation path should start with m/.. + if (temp_der_path[0] != 'm' || temp_der_path[1] != '/') + { + // Malformed Derivation path return + return; + } - // uint32_t coin_type = (encoded_wallet[5 * sequence_no + 34] << 8) | encoded_wallet[5 * sequence_no + 35]; - // uint32_t account = (encoded_wallet[5 * sequence_no + 36] << 8) | encoded_wallet[5 * sequence_no + 37]; + uint32_t coin_type = 0; + uint32_t account = 0; + uint32_t address_index = 0; + + int dig_c = 0; + + // ix will be 0 for scanning coin_type, 1 for scanning account, 2 for scanning address_index + uint8_t ix = 0; + + for (int x = 2; x < path_len; ++x) + { + if (temp_der_path[x] == '/') + { + dig_c = 0; + ix += 2; + } + else + { + // Only process if char is a digit + if (temp_der_path[x] >= '0' && temp_der_path[x] <= '9') + { + if (ix == 0) + { + // Coin type + coin_type *= 10; + coin_type += (int)(temp_der_path[x] - '0'); + } + else if (ix == 1) + { + // Account + account *= 10; + account += (int)(temp_der_path[x] - '0'); + } + else if (ix == 2) + { + // Index + address_index *= 10; + account += (int)(temp_der_path[x] - '0'); + } + dig_c++; + } + } + } + + // PRINTF("\n Coin Type %d \n", coin_type); + // PRINTF("\n Account %d \n", account); + // PRINTF("\n Addr Index %d \n", address_index); + + // Offset the index if any + address_index += address_index_offset; cx_curve_t curve; - *curve_type = encoded_wallet[seek_bytes + 7]; + *curve_type = encoded_wallet[seek_bytes + 1 + path_len]; switch (*curve_type) { case 0: @@ -207,7 +246,7 @@ void generateKeyFromWallet(uint32_t address_index_offset, uint8_t *encoded_walle } // First 4 bytes are version uint8_t seed_len = encoded_wallet[4]; - + deriveArchEthicKeyPair(curve, coin_type, account, address_index, encoded_wallet + 5, seed_len, privateKey, publicKey); } @@ -243,7 +282,7 @@ void deriveArchEthicKeyPair(cx_curve_t curve, uint32_t coin_type, uint32_t accou // uint32_t bip44Path[] = {44 | 0x80000000, coin_type | 0x80000000, account | 0x80000000, 0x80000000, address_index | 0x80000000}; // New Scheme for derivation path is - // m/650'/0'/0' where m/coin_type(650' fixed for now)/account/address_index + // m/650'/0'/0' where m/coin_type/account/address_index uint32_t derivationPath[] = {coin_type | 0x80000000, account | 0x80000000, address_index | 0x80000000}; @@ -296,8 +335,6 @@ void performECDSA(uint8_t *txHash, uint8_t txHashLen, uint32_t address_index_off *sign_len = cx_ecdsa_sign(&privateKey, CX_RND_TRNG, CX_SHA256, txHash, txHashLen, asn_sign + publicKey.W_len + 2, MAX_ENCODE_WALLET_LEN - publicKey.W_len - 2, &info); *sign_len += publicKey.W_len + 2; - - } void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, diff --git a/src/archethic.h b/src/archethic.h index 3e95d28..56b1a30 100644 --- a/src/archethic.h +++ b/src/archethic.h @@ -81,7 +81,7 @@ void generateArchEthicAddress(uint8_t hash_type, uint8_t service_index, uint8_t *encoded_wallet, uint8_t *wallet_len, uint32_t sequence_no, uint8_t *address, uint8_t *address_len, uint32_t seek_bytes, uint32_t address_index_offset); -void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_bip_44, uint8_t *bip44_len, uint32_t *seek_bytes); +void getDerivationPath(uint8_t service_index, uint8_t *encoded_wallet, uint8_t wallet_len, uint8_t sequence_no, char *string_derivation_path, uint8_t *derivation_path_len, uint32_t *seek_bytes); void getTransactionHash(uint8_t *senderAddr, uint8_t senderAddrLen, uint8_t *receiveAddr, uint8_t receiveAddrLen, diff --git a/src/signHash.c b/src/signHash.c index 4a60476..194c4e7 100644 --- a/src/signHash.c +++ b/src/signHash.c @@ -98,19 +98,11 @@ void ui_validate_sign_hash(bool choice) * signing key => address index * returns the Public Key + ASN SIGN */ - // PRINTF("\n Transaction Hash: %.*H \n", g_tx.txHashLen, g_tx.txHash); - // PRINTF("\n Signing Address Index: %d\n", g_tx.address_index); - // PRINTF("\n Encoded Wallet Length: %d \n", g_Wallet.walletLen); - // PRINTF("\n Encoded Wallet: %.*H", g_Wallet.walletLen, g_Wallet.encodedWallet); + performECDSA(g_tx.txHash, g_tx.txHashLen, 0, g_Wallet.encodedWallet, &g_Wallet.walletLen, g_tx.service_index, g_tx.seek_bytes, g_Wallet.encodedWallet, &g_Wallet.walletLen); - // PRINTF("\n Signature: %.*H \n", g_Wallet.walletLen, g_Wallet.encodedWallet); - // PRINTF("\n Sig Len: %d \n", g_Wallet.walletLen); - // PRINTF("\n Txn hash Len: %d \n", g_tx.txHashLen); - // PRINTF("\n Total Len: %d \n", g_tx.txHashLen + g_Wallet.walletLen); - memcpy(G_io_apdu_buffer, g_tx.txHash, g_tx.txHashLen); memcpy(G_io_apdu_buffer + g_tx.txHashLen, g_Wallet.encodedWallet, g_Wallet.walletLen); @@ -197,17 +189,14 @@ void handleSignHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLe uint32_t seek_bytes = 0; // get derivation path for display and seek bytes for current service - uint8_t bip44pathlen; + uint8_t derivationPathLen; memset(g_derivation_path, 0, sizeof(g_derivation_path)); - getDerivationPath(service_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_derivation_path, &bip44pathlen, &seek_bytes); + getDerivationPath(service_index, g_Wallet.encodedWallet, g_Wallet.walletLen, 0, g_derivation_path, &derivationPathLen, &seek_bytes); // get sender address using address index + 1, according to specs V1 g_tx.seek_bytes = seek_bytes; - uint32_t address_index = (g_Wallet.encodedWallet[seek_bytes + 5] << 8) | g_Wallet.encodedWallet[seek_bytes + 6]; - g_tx.address_index = address_index; - // Offset address_index by +1 generateArchEthicAddress(0, service_index, g_Wallet.encodedWallet, &g_Wallet.walletLen, 0, g_tx.senderAddr, &g_tx.senderAddrLen, seek_bytes, 1); diff --git a/tests/manual_testing/test.py b/tests/manual_testing/test.py index f767f62..91dc4de 100644 --- a/tests/manual_testing/test.py +++ b/tests/manual_testing/test.py @@ -21,8 +21,8 @@ port=9999, debug=True) # encrypted_key_plus_wallet = "0401EC530D1BBDF3B1B3E18C6E2330E5CFD1BFD88EB6D84102184CB39EC271793578B469ACBD8EB4F684C41B5DA87712A203AAA910B7964218794E3D3F343835843C44AFFE281D750E6CA526C6FC265167FE37DB9E47828BF80964DAC837E1072CA9954FF1852FF71865B9043BC117BC001C47D76A326A2A2F7CF6B16AB49E9E57F9D5E6D8E1D00D7F1B7E2F986C711DCA060005B2C8F485" -encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" -encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" +encoded_encrypted_key = "04CB3DC7888D6045AE7BB6A2F80FB8919E0D01CFF3407643F22582BA5F7EDCC403D569ED5F9C30CCEE2CE3136BEE0D12C58564EA8D8A244B5E6DFEC04536B0182A97B7E544F03670554D737EF76A948DB0CC5A9928A0F8C11D2DE8923C9E5E3267DBC51B4DDDA7CD496F2F331E0736B4B9" +encoded_encrypted_wallet = "FC6659EFC3B68999B968136940C25FF0FB7241AE7B03C3D0CDCB76D03FE5CC35A2E4F201569DFCB6C26544D99DEB21FA12C7B7BABF38075293" encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet address_index = "00000000" diff --git a/tests/manual_testing/testcase_new.txt b/tests/manual_testing/testcase_new.txt index 9b4877e..d1b5602 100644 --- a/tests/manual_testing/testcase_new.txt +++ b/tests/manual_testing/testcase_new.txt @@ -5,7 +5,7 @@ 20 Master Seed for Onchain Wallet (32 bytes) -6101EA75C066DE8D252100786CD22E0B11532915E855990DE6F359B7DBA4BC91 +1A89B6EEBF7C3B39B2E5AD8B44A6CBD9D59382125BC41DA8EBFFE11E4ED2AF1B No. of services: 01 @@ -17,10 +17,10 @@ Master Seed for Onchain Wallet (32 bytes) 75636F Derivation Path Length: -06 +0C - Derivation Path (6 bytes): [Coin type = 650, account = 0, index = 0] -028A00000000 + Derivation Path (0C:hex Bytes): [Coin type = 650, account = 0, index = 0] +6D2F363530272F30272F3027 Wallet Curve (0:ed25519, 1:nistp256, 2:secp256k1): 02 @@ -33,18 +33,18 @@ Wallet Curve (0:ed25519, 1:nistp256, 2:secp256k1): 00 Encoded Wallet (version,master seed len, master seed, number of services, service name len, service name, derivation path len, derivcation path, wallet curve, hash type): -00000001206101EA75C066DE8D252100786CD22E0B11532915E855990DE6F359B7DBA4BC91010375636F06028A000000000200 +00000001201A89B6EEBF7C3B39B2E5AD8B44A6CBD9D59382125BC41DA8EBFFE11E4ED2AF1B010375636F0C6D2F363530272F30272F30270200 ---------------------------------------------------- Wallet Key (AES256 CTR) for encrypting Onchain Wallet (32 bytes) -477EF7476F0C8402361D57757A3E6F5B0C36EF804E48300128F4031D88A37C29 +0D9771CECDCDEFB29B030F69F23A1329AA56A00C11AF35BC969544CBDC633E21 IV encrypting Onchain Wallet (SHA256(SHA256(Wallet Key)))[0:16] -2C36D83B3F6E910E0753EDD8E74BBB59 +CDA3B3C9822EB14E8B943FACE005244B Encryption of Encoded Wallet (AES256 CTR): -098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D +FC6659EFC3B68999B968136940C25FF0FB7241AE7B03C3D0CDCB76D03FE5CC35A2E4F201569DFCB6C26544D99DEB21FA12C7B7BABF38075293 ---------------------------------------------------- @@ -52,43 +52,41 @@ ECDH Curve (0:ed25519, 1:nistp256, 2:secp256k1): 02 Ephemeral Public Key -041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E98 +04CB3DC7888D6045AE7BB6A2F80FB8919E0D01CFF3407643F22582BA5F7EDCC403D569ED5F9C30CCEE2CE3136BEE0D12C58564EA8D8A244B5E6DFEC04536B0182A Origin Device Public Key 0456ADC116763F07B1CDC6EC8E2453FCB5F67DDD96123C0B4955D7BF82EAB20FF190F871F3C514D2E81391C7FF314F0F18D38899EC43A7085ABE2BD90B0D147F30 ECDH Point x: ECDH(Origin Device Public Key, Ephemeral Private Key) -E6C4A1759DF6C1090F6253CD096D5F66627E62BE7322C5EC580925F38D18E95D +8D35AA4A4F6753D64AFF7991439E7DDDAC85686988A348743BEE52216C746CEF ---------------------------------------------------- AES256 CBC Key: SHA512(SHA512(ECDH Point x))[0:32] -E15A84B6E697FF0F11BF44BF3168E33BFDC48FD0CAD40F38CCFB073373F02CB7 +D038B6163CA7B4C88B0C431E9BD5062AD031D64DA7984DC44E372C2C494D6A61 IV: SHA512(SHA512(ECDH Point x))[32:48] -43FB4D6C24E8A930EF06C7B386A234FA +FFF007E7CD6243BB7473AFAFDCFF2EF7 Encryption of Wallet Key (AES256 CBC): -790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75 +CC5A9928A0F8C11D2DE8923C9E5E3267DBC51B4DDDA7CD496F2F331E0736B4B9 ---------------------------------------------------- Authentication Seed: SHA512(SHA512(ECDH Point x))[48:64] -13AF1023BC0714185903058A13C506EF +8B5647BEE1D2756580104CB65649D7AA Authentication Key: SHA256(Authentication Seed) -42A184D308BE416889556F3D2C115842D1A68AA87E06F0E9B4A789CB52EBC8C6 +0439330175E606DFDE1673F96C4BC699BDDCB2C05535B6B24364AC3B18A11A97 Authentication Tag: HMAC256(Authentication Key, Encrypted Wallet Key)[0:16] -8BFA38917BF72DDBBB0A72E4EE839024 +97B7E544F03670554D737EF76A948DB0 ---------------------------------------------------- Encoding of Encrypted Wallet Key(ephemeral public key, authentication tag, encrypted wallet key): -041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75 +04CB3DC7888D6045AE7BB6A2F80FB8919E0D01CFF3407643F22582BA5F7EDCC403D569ED5F9C30CCEE2CE3136BEE0D12C58564EA8D8A244B5E6DFEC04536B0182A97B7E544F03670554D737EF76A948DB0CC5A9928A0F8C11D2DE8923C9E5E3267DBC51B4DDDA7CD496F2F331E0736B4B9 ---------------------------------------------------- Interactive Elixir (1.13.3) - press Ctrl+C to exit (type h() ENTER for help) -iex(1)> -BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo - (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution +iex(1)> \ No newline at end of file diff --git a/tests/manual_testing/wallet_encoder_new.ex b/tests/manual_testing/wallet_encoder_new.ex index 7087ee0..af24415 100644 --- a/tests/manual_testing/wallet_encoder_new.ex +++ b/tests/manual_testing/wallet_encoder_new.ex @@ -42,12 +42,20 @@ master_seed = :crypto.strong_rand_bytes(32) service_name = "uco" # {_ok, service_name} = Base.encode16("uco", case: :upper ) -{_ok, derivation_path_length} = Base.decode16("06") +# {_ok, derivation_path_length} = Base.decode16("06") + +# {_ok, coin_type} = Base.decode16("028A") +# {_ok, account} = Base.decode16("0000") +# {_ok, address_index} = Base.decode16("0000") +# derivation_path = coin_type <> account <> address_index + +{_ok, derivation_path_length} = Base.decode16("0C") + +derivation_path = "m/650'/0'/0'" + +# size_str = derivation_path |> String.length |> Integer.to_string(16) + -{_ok, coin_type} = Base.decode16("028A") -{_ok, account} = Base.decode16("0000") -{_ok, address_index} = Base.decode16("0000") -derivation_path = coin_type <> account <> address_index {_ok, wallet_curve} = Base.decode16("02") {_ok, hash_type} = Base.decode16("00") @@ -74,7 +82,7 @@ IO.puts(Base.encode16(service_name)) IO.puts("\n Derivation Path Length: ") IO.puts(Base.encode16(derivation_path_length)) -IO.puts("\n Derivation Path (6 bytes): [Coin type = 650, account = 0, index = 0]") +IO.puts("\n Derivation Path (" <> Base.encode16(derivation_path_length) <>":hex Bytes): [Coin type = 650, account = 0, index = 0]") IO.puts(Base.encode16(derivation_path)) IO.puts("\nWallet Curve (0:ed25519, 1:nistp256, 2:secp256k1): ") diff --git a/tests/test_arch_addr.py b/tests/test_arch_addr.py index 7e33f66..15164dd 100644 --- a/tests/test_arch_addr.py +++ b/tests/test_arch_addr.py @@ -2,8 +2,8 @@ def test_get_arch_addr(cmd, hid): # Testing with a predefined onchain wallet - encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" - encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" + encoded_encrypted_key = "04CB3DC7888D6045AE7BB6A2F80FB8919E0D01CFF3407643F22582BA5F7EDCC403D569ED5F9C30CCEE2CE3136BEE0D12C58564EA8D8A244B5E6DFEC04536B0182A97B7E544F03670554D737EF76A948DB0CC5A9928A0F8C11D2DE8923C9E5E3267DBC51B4DDDA7CD496F2F331E0736B4B9" + encoded_encrypted_wallet = "FC6659EFC3B68999B968136940C25FF0FB7241AE7B03C3D0CDCB76D03FE5CC35A2E4F201569DFCB6C26544D99DEB21FA12C7B7BABF38075293" encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet diff --git a/tests/test_sign_hash.py b/tests/test_sign_hash.py index 460400d..7332e5f 100644 --- a/tests/test_sign_hash.py +++ b/tests/test_sign_hash.py @@ -11,8 +11,8 @@ def test_sign_txn_hash(cmd, hid): # Testing with a predefined onchain wallet - encoded_encrypted_key = "041513BB64C3F276D6062E6BF961B243C14D038A0736B69C445834CAFD36277015BE7CCB6D145D5D56FCEF323FBFA702836EA56CFF8BF35E086CD395F266D60E988BFA38917BF72DDBBB0A72E4EE839024790EB79193B4324D2D87A5115CAE6E79193E8E4AE4B5DC9681FC89E02944BE75" - encoded_encrypted_wallet = "098491FEBC7C6473E7A01177B83F9C7167C8110A827474574106E47781FDB65ED087A965F1B6CDF47C5F043FD02A1CC1B12E5D" + encoded_encrypted_key = "04CB3DC7888D6045AE7BB6A2F80FB8919E0D01CFF3407643F22582BA5F7EDCC403D569ED5F9C30CCEE2CE3136BEE0D12C58564EA8D8A244B5E6DFEC04536B0182A97B7E544F03670554D737EF76A948DB0CC5A9928A0F8C11D2DE8923C9E5E3267DBC51B4DDDA7CD496F2F331E0736B4B9" + encoded_encrypted_wallet = "FC6659EFC3B68999B968136940C25FF0FB7241AE7B03C3D0CDCB76D03FE5CC35A2E4F201569DFCB6C26544D99DEB21FA12C7B7BABF38075293" encrypted_key_plus_wallet = encoded_encrypted_key + encoded_encrypted_wallet