# Passphrase Redesign In 1.9.0 / 2.3.0

On the T1, passphrase must be entered on the host PC and sent to Trezor. On the TT, the
user can choose whether to enter the passphrase on host or on Trezor's touch screen.

In versions 1.9.0 and 2.3.0 we have redesigned how the passphrase is
communicated between the Host and the Device. The new design is documented
thoroughly in [passphrase.md](passphrase.md) and this document should help
with the transition from the old design.

## New features

* Passphrase flow is now identical for T1 and TT.
* By keeping track of _sessions_, it is possible to avoid having to send passphrase repeatedly.
* The choice between entering on Host or Device for TT has been moved from Device to Host.
* Multiple passphrases are cached simultaneously.

## Backwards compatibility

T1 1.9.0 is fully backwards-compatible and works with existing Host code.

TT 2.3.0 communicating with old Host software degrades to T1-level features: entering
passphrase on device will not be available, and on-device passphrase caching via the
`state` field will not be available.

As a workaround, it is possible to use the "passphrase always on device" feature on the
new TT firmware. When enabled, the passphrase flow is completely hidden from the Host
software, and the Device itself prompts the user to enter the passphrase.

## Implementation guide

### Protobuf changes

Protobuf has built-in backwards compatibility mechanisms, so a conforming implementation
should continue to work with old protobuf definitions.

To restore support for TT on-device passphrase entry, and to make use of the new
features, you will need to update to newer protobuf definitions from `trezor-common`
(TODO: link to commit in trezor-common).

The gist of the changes is:

- `PassphraseRequest.on_device` was deprecated, and renamed to `_on_device`. New Devices
  will never send this field.
- Corresponding field `PassphraseAck.on_device` was added.
- `PassphraseAck.state` was deprecated, and renamed to `_state`. It is retained for
  code compatibility, but the field should never be set.
- `PassphraseStateRequest`/`PassphraseStateAck` messages were deprecated, and renamed
  with a `Deprecated_` prefix. New Devices will not send or accept these messages.
- `Initialize.state` was renamed to `Initialize.session_id`.
- Corresponding field `Features.session_id` was added. New Devices will always send this
  field in response to `Initialize` call.
- A new value `Capability_PassphraseEntry` was added to the `Features.Capability`
  enum. This capability will be sent from a Device that supports on-device passphrase
  entry (currently only TT).

### Restoring on-device entry for TT

The Host software reacts to a `PassphraseRequest` message by prompting the user for a
passphrase and sending it in the `PassphraseAck.passphrase` field.

A new UI element should be added: when the passphrase prompt is displayed on Host, there
should be an option to "enter passphrase on device". When the user selects this option,
the Host must send a `PassphraseAck(passphrase=null, on_device=true)`.

The "enter passphrase on device" option should be displayed when `Features.capabilities`
contain the `Capability_PassphraseEntry` value, regardless of reported Trezor version or
model. Firmwares older than 2.3.0 or 1.9.0 never set this value, so this ensures
forwards and backwards compatibility.

### Cross-version compatibility for TT

TT version \< 2.3.0 will send `PassphraseRequest(_on_device=true)` if the user selected
on-device entry. Neither T1 nor TT >= 2.3.0 will ever set this field to true.

If the Host receives `PassphraseRequest(_on_device=true)`, it should immediately respond
with `PassphraseAck()` with no fields set.

TT version \< 2.3.0 will send `Deprecated_PassphraseStateRequest(state=[bytes])` after
receiving `PassphraseAck`. The Host should immediately respond with
`Deprecated_PassphraseStateAck()` with no fields set. If the Host does session
management, it should store the value of `state` as the session ID.

### Triggering passphrase prompt

Use `GetAddress(coin_name="Testnet", address_n=[44'/1'/0'/0/0])` (the first address of
the first account of Testnet) to ensure that the Device asks for a passphrase if
needed, and caches it for future use.

### Validating passphrases

You can store the result of the above call, and in the future, compare it to a newly
received address. This is a good way to check if the user is using the same passphrase
as last time.

Do not store user-entered passphrases for the purpose of validation, even in hashed,
encrypted, or otherwise obfuscated format.

### Session support

A call to `Initialize` can include a `session_id` field. When starting a new user
session, this field should be left empty.

The response `Features` message will always include a `session_id` field. The value of
this field should be stored. When calling `Initialize` again, the stored value should
be sent as `session_id`. If the received `Features.session_id` is the same, it means
that session was resumed successfully and the user will not be prompted for passphrase.

```
--> Initialize()
<-- Features(session_id=0xABCDEF, ...)

--> Initialize(session_id=0xABCDEF)
<-- Features(session_id=0xABCDEF)
# (session resumed successfully)

--> Initialize(session_id=0xABCDEF)
<-- Features(session_id=0x123456)
# (session was not resumed, user will be prompted for passphrase again)
```

Session support is identical on T1 and TT, and both models support multiple sessions,
i.e., it is possible to seamlessly switch between using multiple passphrases.

### Cross-version compatible algorithm summary

The following algorithm will ensure that your Host application works properly with
both T1 and TT with both older and newer firmwares.

1. If you have a session ID stored, call `Initialize(session_id=stored_session_id)`
2. Check the value of `Features.session_id`. If it is identical to `stored_session_id`,
   the session was resumed and user will not need to be prompted for a passphrase.
   1. If `Features.session_id` is not set, you are communicating with an older Device.
      Do not store the null value as session ID.
   2. Otherwise store the value as `stored_session_id`.
3. When you receive a `PassphraseRequest(_on_device=true)`, respond with
   `PassphraseAck()` with no fields set.
4. When you receive a `PassphraseRequest`, prompt the user for passphrase.
   1. If `Features.capabilities` contains value `Capability_PassphraseEntry`, display a
      UI element that allows the user to enter passphrase on-device.
   2. If the user chooses this option, send `PassphraseAck(passphrase=null, on_device=true)`
   3. If the user enters the passphrase in your application, send
      `PassphraseAck(passphrase="user entered passphrase", on_device=false)`
5. When you receive a `Deprecated_PassphraseStateRequest(state=...)`, store the value
   of `state` as `stored_session_id`, and respond with `Deprecated_PassphraseStateAck`
   with no fields set.

Note: up to 64 bytes may be required to store the session ID. Firmwares < 2.3.0 use a
64-byte value, newer firmwares use a 32-byte value.
