mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-18 20:38:10 +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 {
|
||||
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
|
||||
apps.common
|
||||
import apps.common
|
||||
apps.common.address_mac
|
||||
import apps.common.address_mac
|
||||
apps.common.address_type
|
||||
import apps.common.address_type
|
||||
apps.common.authorization
|
||||
|
@ -5,6 +5,7 @@ from trezor.enums import InputScriptType
|
||||
from trezor.messages import 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 . import addresses
|
||||
@ -64,6 +65,7 @@ async def get_address(
|
||||
else:
|
||||
address_qr = address # base58 address
|
||||
|
||||
mac: bytes | None = None
|
||||
multisig_xpub_magic = coin.xpub_magic
|
||||
if msg.multisig:
|
||||
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
|
||||
):
|
||||
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.multisig:
|
||||
@ -101,4 +111,4 @@ async def get_address(
|
||||
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]:
|
||||
coin = get_coin_by_name(coin_name)
|
||||
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)
|
||||
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):
|
||||
address: "str"
|
||||
mac: "bytes | None"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
address: "str",
|
||||
mac: "bytes | None" = None,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
@ -226,6 +226,27 @@ class TestAddress(unittest.TestCase):
|
||||
for path, input_type in incorrect_derivation_paths:
|
||||
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__':
|
||||
unittest.main()
|
||||
|
@ -8,6 +8,7 @@ GetAddress.address_n max_count:8
|
||||
GetAddress.coin_name max_size:21
|
||||
|
||||
Address.address max_size:130
|
||||
Address.mac type:FT_IGNORE
|
||||
|
||||
SignTx.coin_name max_size:21
|
||||
|
||||
|
@ -128,7 +128,12 @@ def get_public_node(
|
||||
|
||||
|
||||
@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",
|
||||
coin_name: str,
|
||||
n: "Address",
|
||||
|
@ -1024,14 +1024,17 @@ class Address(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 30
|
||||
FIELDS = {
|
||||
1: protobuf.Field("address", "string", repeated=False, required=True),
|
||||
2: protobuf.Field("mac", "bytes", repeated=False, required=False),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
address: "str",
|
||||
mac: Optional["bytes"] = None,
|
||||
) -> None:
|
||||
self.address = address
|
||||
self.mac = mac
|
||||
|
||||
|
||||
class GetOwnershipId(protobuf.MessageType):
|
||||
|
Loading…
Reference in New Issue
Block a user