mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 12:28:09 +00:00
chore(core): Add mac field to Address message.
[no changelog]
This commit is contained in:
parent
2ac3d0acb4
commit
d0c3a6a2fa
@ -118,6 +118,7 @@ message GetAddress {
|
|||||||
*/
|
*/
|
||||||
message Address {
|
message Address {
|
||||||
required string address = 1; // Coin address in Base58 encoding
|
required string address = 1; // Coin address in Base58 encoding
|
||||||
|
optional bytes mac = 2; // Address authentication code
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -292,6 +292,8 @@ apps.bitcoin.writers
|
|||||||
import apps.bitcoin.writers
|
import apps.bitcoin.writers
|
||||||
apps.common
|
apps.common
|
||||||
import apps.common
|
import apps.common
|
||||||
|
apps.common.address_mac
|
||||||
|
import apps.common.address_mac
|
||||||
apps.common.address_type
|
apps.common.address_type
|
||||||
import apps.common.address_type
|
import apps.common.address_type
|
||||||
apps.common.authorization
|
apps.common.authorization
|
||||||
|
@ -5,6 +5,7 @@ from trezor.enums import InputScriptType
|
|||||||
from trezor.messages import Address
|
from trezor.messages import Address
|
||||||
from trezor.ui.layouts import show_address
|
from trezor.ui.layouts import show_address
|
||||||
|
|
||||||
|
from apps.common.address_mac import get_address_mac
|
||||||
from apps.common.paths import address_n_to_str, validate_path
|
from apps.common.paths import address_n_to_str, validate_path
|
||||||
|
|
||||||
from . import addresses
|
from . import addresses
|
||||||
@ -64,6 +65,7 @@ async def get_address(
|
|||||||
else:
|
else:
|
||||||
address_qr = address # base58 address
|
address_qr = address # base58 address
|
||||||
|
|
||||||
|
mac: bytes | None = None
|
||||||
multisig_xpub_magic = coin.xpub_magic
|
multisig_xpub_magic = coin.xpub_magic
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
if coin.segwit and not msg.ignore_xpub_magic:
|
if coin.segwit and not msg.ignore_xpub_magic:
|
||||||
@ -77,6 +79,14 @@ async def get_address(
|
|||||||
and coin.xpub_magic_multisig_segwit_p2sh is not None
|
and coin.xpub_magic_multisig_segwit_p2sh is not None
|
||||||
):
|
):
|
||||||
multisig_xpub_magic = coin.xpub_magic_multisig_segwit_p2sh
|
multisig_xpub_magic = coin.xpub_magic_multisig_segwit_p2sh
|
||||||
|
else:
|
||||||
|
# Attach a MAC for single-sig addresses, but only if the path is standard
|
||||||
|
# or if the user explicitly confirms a non-standard path.
|
||||||
|
if msg.show_display or (
|
||||||
|
keychain.is_in_keychain(msg.address_n)
|
||||||
|
and validate_path_against_script_type(coin, msg)
|
||||||
|
):
|
||||||
|
mac = get_address_mac(address, coin.slip44, keychain)
|
||||||
|
|
||||||
if msg.show_display:
|
if msg.show_display:
|
||||||
if msg.multisig:
|
if msg.multisig:
|
||||||
@ -101,4 +111,4 @@ async def get_address(
|
|||||||
ctx, address=address_short, address_qr=address_qr, title=title
|
ctx, address=address_short, address_qr=address_qr, title=title
|
||||||
)
|
)
|
||||||
|
|
||||||
return Address(address=address)
|
return Address(address=address, mac=mac)
|
||||||
|
@ -238,7 +238,7 @@ async def get_keychain_for_coin(
|
|||||||
) -> tuple[Keychain, coininfo.CoinInfo]:
|
) -> tuple[Keychain, coininfo.CoinInfo]:
|
||||||
coin = get_coin_by_name(coin_name)
|
coin = get_coin_by_name(coin_name)
|
||||||
schemas = get_schemas_for_coin(coin)
|
schemas = get_schemas_for_coin(coin)
|
||||||
slip21_namespaces = [[b"SLIP-0019"]]
|
slip21_namespaces = [[b"SLIP-0019"], [b"SLIP-0024"]]
|
||||||
keychain = await get_keychain(ctx, coin.curve_name, schemas, slip21_namespaces)
|
keychain = await get_keychain(ctx, coin.curve_name, schemas, slip21_namespaces)
|
||||||
return keychain, coin
|
return keychain, coin
|
||||||
|
|
||||||
|
32
core/src/apps/common/address_mac.py
Normal file
32
core/src/apps/common/address_mac.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from trezor import utils, wire
|
||||||
|
from trezor.crypto import hashlib, hmac
|
||||||
|
|
||||||
|
from .writers import write_bitcoin_varint, write_bytes_unchecked, write_uint32_le
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from apps.common.keychain import Keychain
|
||||||
|
|
||||||
|
_ADDRESS_MAC_KEY_PATH = [b"SLIP-0024", b"Address MAC key"]
|
||||||
|
|
||||||
|
|
||||||
|
def check_address_mac(
|
||||||
|
address: str, mac: bytes, slip44: int, keychain: Keychain
|
||||||
|
) -> None:
|
||||||
|
expected_mac = get_address_mac(address, slip44, keychain)
|
||||||
|
if len(mac) != hashlib.sha256.digest_size or not utils.consteq(expected_mac, mac):
|
||||||
|
raise wire.DataError("Invalid address MAC.")
|
||||||
|
|
||||||
|
|
||||||
|
def get_address_mac(address: str, slip44: int, keychain: Keychain) -> bytes:
|
||||||
|
# k = Key(m/"SLIP-0024"/"Address MAC key")
|
||||||
|
node = keychain.derive_slip21(_ADDRESS_MAC_KEY_PATH)
|
||||||
|
|
||||||
|
# mac = HMAC-SHA256(key = k, msg = slip44 || address)
|
||||||
|
mac = utils.HashWriter(hmac(hmac.SHA256, node.key()))
|
||||||
|
address_bytes = address.encode()
|
||||||
|
write_uint32_le(mac, slip44)
|
||||||
|
write_bitcoin_varint(mac, len(address_bytes))
|
||||||
|
write_bytes_unchecked(mac, address_bytes)
|
||||||
|
return mac.get_digest()
|
@ -474,11 +474,13 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class Address(protobuf.MessageType):
|
class Address(protobuf.MessageType):
|
||||||
address: "str"
|
address: "str"
|
||||||
|
mac: "bytes | None"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
address: "str",
|
address: "str",
|
||||||
|
mac: "bytes | None" = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -226,6 +226,27 @@ class TestAddress(unittest.TestCase):
|
|||||||
for path, input_type in incorrect_derivation_paths:
|
for path, input_type in incorrect_derivation_paths:
|
||||||
self.assertFalse(self.validate(path, coin, input_type))
|
self.assertFalse(self.validate(path, coin, input_type))
|
||||||
|
|
||||||
|
def test_address_mac(self):
|
||||||
|
from apps.common.address_mac import check_address_mac, get_address_mac
|
||||||
|
from apps.common.keychain import Keychain
|
||||||
|
from apps.common.paths import AlwaysMatchingSchema
|
||||||
|
|
||||||
|
VECTORS = (
|
||||||
|
('Bitcoin', '1DyHzbQUoQEsLxJn6M7fMD8Xdt1XvNiwNE', '9cf7c230041d6ed95b8273bd32e023d3f227ec8c44257f6463c743a4b4add028'),
|
||||||
|
('Testnet', 'mm6kLYbGEL1tGe4ZA8xacfgRPdW1NLjCbZ', '4375089e50423505dc3480e6e85b0ba37a52bd1e009db5d260b6329f22c950d9')
|
||||||
|
)
|
||||||
|
seed = bip39.seed(' '.join(['all'] * 12), '')
|
||||||
|
|
||||||
|
for coin_name, address, mac in VECTORS:
|
||||||
|
coin = coins.by_name(coin_name)
|
||||||
|
mac = unhexlify(mac)
|
||||||
|
keychain = Keychain(seed, coin.curve_name, [AlwaysMatchingSchema], slip21_namespaces=[[b"SLIP-0024"]])
|
||||||
|
self.assertEqual(get_address_mac(address, coin.slip44, keychain), mac)
|
||||||
|
check_address_mac(address, mac, coin.slip44, keychain)
|
||||||
|
with self.assertRaises(wire.DataError):
|
||||||
|
mac = bytes([mac[0]^1]) + mac[1:]
|
||||||
|
check_address_mac(address, mac, coin.slip44, keychain)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -8,6 +8,7 @@ GetAddress.address_n max_count:8
|
|||||||
GetAddress.coin_name max_size:21
|
GetAddress.coin_name max_size:21
|
||||||
|
|
||||||
Address.address max_size:130
|
Address.address max_size:130
|
||||||
|
Address.mac type:FT_IGNORE
|
||||||
|
|
||||||
SignTx.coin_name max_size:21
|
SignTx.coin_name max_size:21
|
||||||
|
|
||||||
|
@ -128,7 +128,12 @@ def get_public_node(
|
|||||||
|
|
||||||
|
|
||||||
@expect(messages.Address, field="address", ret_type=str)
|
@expect(messages.Address, field="address", ret_type=str)
|
||||||
def get_address(
|
def get_address(*args: Any, **kwargs: Any):
|
||||||
|
return get_authenticated_address(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@expect(messages.Address)
|
||||||
|
def get_authenticated_address(
|
||||||
client: "TrezorClient",
|
client: "TrezorClient",
|
||||||
coin_name: str,
|
coin_name: str,
|
||||||
n: "Address",
|
n: "Address",
|
||||||
|
@ -1024,14 +1024,17 @@ class Address(protobuf.MessageType):
|
|||||||
MESSAGE_WIRE_TYPE = 30
|
MESSAGE_WIRE_TYPE = 30
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
1: protobuf.Field("address", "string", repeated=False, required=True),
|
1: protobuf.Field("address", "string", repeated=False, required=True),
|
||||||
|
2: protobuf.Field("mac", "bytes", repeated=False, required=False),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
address: "str",
|
address: "str",
|
||||||
|
mac: Optional["bytes"] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.address = address
|
self.address = address
|
||||||
|
self.mac = mac
|
||||||
|
|
||||||
|
|
||||||
class GetOwnershipId(protobuf.MessageType):
|
class GetOwnershipId(protobuf.MessageType):
|
||||||
|
Loading…
Reference in New Issue
Block a user