diff --git a/src/apps/common/signverify.py b/src/apps/common/signverify.py index 53468f62df..7b5c6b86b4 100644 --- a/src/apps/common/signverify.py +++ b/src/apps/common/signverify.py @@ -1,15 +1,26 @@ +from micropython import const from trezor.crypto.hashlib import sha256 - -from apps.wallet.sign_tx.signing import write_varint +from trezor.utils import chunks from apps.common.hash_writer import HashWriter +from apps.wallet.sign_tx.signing import write_varint def message_digest(coin, message): - h = HashWriter(sha256) write_varint(h, len(coin.signed_message_header)) h.extend(coin.signed_message_header) write_varint(h, len(message)) h.extend(message) - return sha256(h.get_digest()).digest() + + +def split_message(message): + chars_per_line = const(18) + message = stringify_message(message) + lines = chunks(message, chars_per_line) + return lines + + +def stringify_message(message): + # TODO: account for invalid UTF-8 sequences + return str(message, 'utf-8') diff --git a/src/apps/wallet/sign_message.py b/src/apps/wallet/sign_message.py index 1eab1a7092..49add9431d 100644 --- a/src/apps/wallet/sign_message.py +++ b/src/apps/wallet/sign_message.py @@ -1,29 +1,32 @@ from trezor import ui +from trezor.crypto.curve import secp256k1 +from trezor.messages.MessageSignature import MessageSignature +from trezor.ui.text import Text +from apps.common import coins, seed +from apps.common.confirm import require_confirm +from apps.common.signverify import message_digest, split_message -async def layout_sign_message(ctx, msg): - from trezor.messages.MessageSignature import MessageSignature - from trezor.crypto.curve import secp256k1 - from ..common import coins - from ..common import seed - from ..common.signverify import message_digest - - ui.display.clear() - ui.display.text(10, 30, 'Signing message', - ui.BOLD, ui.LIGHT_GREEN, ui.BG) - ui.display.text(10, 60, msg.message, ui.MONO, ui.FG, ui.BG) - +async def sign_message(ctx, msg): + message = msg.message + address_n = msg.address_n coin_name = msg.coin_name or 'Bitcoin' coin = coins.by_name(coin_name) + await confirm_sign_message(ctx, message) + node = await seed.get_root(ctx) - node.derive_path(msg.address_n) - + node.derive_path(address_n) seckey = node.private_key() + address = node.address(coin.address_type) - - digest = message_digest(coin, msg.message) - + digest = message_digest(coin, message) signature = secp256k1.sign(seckey, digest) return MessageSignature(address=address, signature=signature) + + +async def confirm_sign_message(ctx, message): + message = split_message(message) + content = Text('Sign message', ui.ICON_CONFIRM, ui.MONO, *message) + await require_confirm(ctx, content) diff --git a/src/apps/wallet/verify_message.py b/src/apps/wallet/verify_message.py index a67dcec386..d6d44b18c4 100644 --- a/src/apps/wallet/verify_message.py +++ b/src/apps/wallet/verify_message.py @@ -1,35 +1,41 @@ -from trezor import ui +from trezor import ui, wire +from trezor.crypto import base58 +from trezor.crypto.curve import secp256k1 +from trezor.crypto.hashlib import ripemd160, sha256 +from trezor.messages.FailureType import ProcessError +from trezor.messages.Success import Success +from trezor.ui.text import Text +from apps.common import address_type, coins +from apps.common.confirm import require_confirm +from apps.common.signverify import message_digest, split_message -async def layout_verify_message(ctx, msg): - from trezor.messages.Success import Success - from trezor.crypto.curve import secp256k1 - from trezor.crypto.hashlib import ripemd160, sha256 - from trezor.crypto import base58 - from ..common import address_type - from ..common import coins - from ..common.signverify import message_digest - +async def verify_message(ctx, msg): + message = msg.message + address = msg.address + signature = msg.signature coin_name = msg.coin_name or 'Bitcoin' coin = coins.by_name(coin_name) - digest = message_digest(coin, msg.message) - pubkey = secp256k1.verify_recover(msg.signature, digest) + await confirm_verify_message(ctx, message) + + digest = message_digest(coin, message) + pubkey = secp256k1.verify_recover(signature, digest) if not pubkey: - raise ValueError('Invalid signature') + raise wire.FailureError(ProcessError, 'Invalid signature') - raw_address = base58.decode_check(msg.address) - at, pkh = address_type.split(coin, raw_address) + raw_address = base58.decode_check(address) + _, pkh = address_type.split(coin, raw_address) pkh2 = ripemd160(sha256(pubkey).digest()).digest() if pkh != pkh2: - raise ValueError('Invalid signature') - - ui.display.clear() - ui.display.text(10, 30, 'Verifying message', - ui.BOLD, ui.LIGHT_GREEN, ui.BG) - ui.display.text(10, 60, msg.message, ui.MONO, ui.FG, ui.BG) - ui.display.text(10, 80, msg.address, ui.MONO, ui.FG, ui.BG) + raise wire.FailureError(ProcessError, 'Invalid signature') return Success(message='Message verified') + + +async def confirm_verify_message(ctx, message): + message = split_message(message) + content = Text('Verify message', ui.ICON_CONFIRM, ui.MONO, *message) + await require_confirm(ctx, content)