feat(core, python): create secure input functionality

grdddj/secure_input
grdddj 2 years ago
parent d655dbf228
commit 4152349330

@ -440,3 +440,21 @@ message Nonce {
required bytes nonce = 1; // a 32-byte random value generated by Trezor
}
/**
* Request: Request for secure input
* @next SecureInput
* @next Failure
*/
message GetSecureInput {
optional string prompt = 1 [default="Secure input"];
optional uint32 max_length = 2 [default=99];
}
/**
* Response: Secure input text
* @end
*/
message SecureInput {
required string text = 1;
}

@ -350,4 +350,8 @@ enum MessageType {
MessageType_WebAuthnCredentials = 801 [(wire_out) = true];
MessageType_WebAuthnAddResidentCredential = 802 [(wire_in) = true];
MessageType_WebAuthnRemoveResidentCredential = 803 [(wire_in) = true];
// Others
MessageType_GetSecureInput = 900 [(wire_in) = true];
MessageType_SecureInput = 901 [(wire_out) = true];
}

@ -382,6 +382,8 @@ apps.misc.get_ecdh_session_key
import apps.misc.get_ecdh_session_key
apps.misc.get_entropy
import apps.misc.get_entropy
apps.misc.secure_input
import apps.misc.secure_input
apps.misc.sign_identity
import apps.misc.sign_identity
apps.workflow_handlers

@ -0,0 +1,15 @@
from typing import TYPE_CHECKING
from trezor.messages import SecureInput
from trezor.ui.components.tt.passphrase import PassphraseKeyboard as Keyboard
if TYPE_CHECKING:
from trezor.wire import Context
from trezor.messages import GetSecureInput
async def secure_input(ctx: Context, msg: GetSecureInput) -> SecureInput:
keyboard = Keyboard(msg.prompt, msg.max_length)
text = await ctx.wait(keyboard)
return SecureInput(text=text)

@ -80,6 +80,8 @@ def find_message_handler_module(msg_type: int) -> str:
return "apps.misc.get_ecdh_session_key"
if msg_type == MessageType.CipherKeyValue:
return "apps.misc.cipher_key_value"
if msg_type == MessageType.GetSecureInput:
return "apps.misc.secure_input"
if not utils.BITCOIN_ONLY:
if msg_type == MessageType.SetU2FCounter:

@ -227,3 +227,5 @@ if not utils.BITCOIN_ONLY:
WebAuthnCredentials = 801
WebAuthnAddResidentCredential = 802
WebAuthnRemoveResidentCredential = 803
GetSecureInput = 900
SecureInput = 901

@ -228,6 +228,8 @@ if TYPE_CHECKING:
WebAuthnCredentials = 801
WebAuthnAddResidentCredential = 802
WebAuthnRemoveResidentCredential = 803
GetSecureInput = 900
SecureInput = 901
class BinanceOrderType(IntEnum):
OT_UNKNOWN = 0

@ -384,6 +384,36 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["HDNodeType"]:
return isinstance(msg, cls)
class GetSecureInput(protobuf.MessageType):
prompt: "str"
max_length: "int"
def __init__(
self,
*,
prompt: "str | None" = None,
max_length: "int | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["GetSecureInput"]:
return isinstance(msg, cls)
class SecureInput(protobuf.MessageType):
text: "str"
def __init__(
self,
*,
text: "str",
) -> None:
pass
@classmethod
def is_type_of(cls, msg: protobuf.MessageType) -> TypeGuard["SecureInput"]:
return isinstance(msg, cls)
class MultisigRedeemScriptType(protobuf.MessageType):
pubkeys: "list[HDNodePathType]"
signatures: "list[bytes]"

@ -14,7 +14,7 @@
# You should have received a copy of the License along with this library.
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional
import click
@ -38,6 +38,19 @@ def get_entropy(client: "TrezorClient", size: int) -> str:
return misc.get_entropy(client, size).hex()
@cli.command()
@click.option("-p", "--prompt", help="Prompt to show on device")
@click.option("-m", "--max-length", type=int, help="Max length of the input")
@with_client
def secure_input(
client: "TrezorClient",
prompt: Optional[str] = None,
max_length: Optional[int] = None,
) -> str:
"""Get secure input from device."""
return misc.get_secure_input(client, prompt, max_length)
@cli.command()
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/10016'/0")
@click.argument("key")

@ -67,6 +67,7 @@ COMMAND_ALIASES = {
"load-device": device.load,
"self-test": device.self_test,
"get-entropy": crypto.get_entropy,
"secure-input": crypto.secure_input,
"encrypt-keyvalue": crypto.encrypt_keyvalue,
"decrypt-keyvalue": crypto.decrypt_keyvalue,
# currency name aliases:

@ -253,6 +253,8 @@ class MessageType(IntEnum):
WebAuthnCredentials = 801
WebAuthnAddResidentCredential = 802
WebAuthnRemoveResidentCredential = 803
GetSecureInput = 900
SecureInput = 901
class FailureType(IntEnum):
@ -916,6 +918,37 @@ class HDNodeType(protobuf.MessageType):
self.private_key = private_key
class GetSecureInput(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 900
FIELDS = {
1: protobuf.Field("prompt", "string", repeated=False, required=False),
2: protobuf.Field("max_length", "uint32", repeated=False, required=False),
}
def __init__(
self,
*,
prompt: Optional["str"] = 'Secure input',
max_length: Optional["int"] = 99,
) -> None:
self.prompt = prompt
self.max_length = max_length
class SecureInput(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 901
FIELDS = {
1: protobuf.Field("text", "string", repeated=False, required=True),
}
def __init__(
self,
*,
text: "str",
) -> None:
self.text = text
class MultisigRedeemScriptType(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {

@ -30,6 +30,15 @@ def get_entropy(client: "TrezorClient", size: int) -> "MessageType":
return client.call(messages.GetEntropy(size=size))
@expect(messages.SecureInput, field="text", ret_type=str)
def get_secure_input(
client: "TrezorClient",
prompt: Optional[str] = None,
max_length: Optional[int] = None,
) -> "MessageType":
return client.call(messages.GetSecureInput(prompt=prompt, max_length=max_length))
@expect(messages.SignedIdentity)
def sign_identity(
client: "TrezorClient",

Loading…
Cancel
Save