Hello there, I would like to implement a PIN feature. I would like to write here the motivation, implementation details and potential problems / design choices to make. As well as get some feedback and discussion going.
Motivation
Since you can use rbw as an ssh-agent, it’s very convenient to use it for SSH keys. However, typing my long master password every time I push a local repository is inconvenient.
I’d like to let users configure a short (but still secure) PIN for convenience and security 1
We could even leverage the age plugin ecosystem so that the vault can be unlocked using a hardware key or macOS Touch ID via an age plugin.
Design
dek - master symmetric key which decrypts the contents of your vault. Held in memory by the rbw-agent
local_secret - 32-byte secret persisted via a backend
backend - either encrypt local_secret to disk with age (and bound to device via a plugin) or simply in the os keyring.
PIN - arbitrary length user inputted string
kek - key derived from PIN and local_secret with kdf (argon2id)
wrapped_dek - dek wrapped with the kek
pin_state - [wrapped_dek+nonce, salt+argon2params for derivingkek, backend] serialized to disk
The cli api will expose three commands
rbw pin set
- Generates and stores
local_secret via backend.
- Prompts user for a
PIN (with confirmation).
- Wraps
dek → wrapped_dek and writes pin_state.
rbw pin status
- Shows whether
pin_state exists, and which backend is used (age / keyring).
rbw pin clear
- Deletes
pin_state and local_secret.
At rbw unlock, we simply check that a pin_state exists in the actions::unlock_state function, ask for pin, decrypt and store the decrypted dek to the agent's state.
Considerations
- I do not think an expiry time / limited tries is worth implementing given that these are all defeated by rolling back
pin_state.
- An attacker who can run arbitrary commands could brute force a short pin very quickly, assuming the
backend (e.g keyring) is unlocked. Doesn't apply to hardware key style age plugins.
- If the user rotates their keys and syncs the local database, the pin becomes invalid. A potential solution would be to keep a hash of the
dek in pin_state and clear the pin if the rotated hash doesn't match.
- If the user stores the local secret with
age-plugin-yubikey, we can allow them to use an empty pin for maximum convenience.
- insert obvious security flaw I have missed here
Hello there, I would like to implement a PIN feature. I would like to write here the motivation, implementation details and potential problems / design choices to make. As well as get some feedback and discussion going.
Motivation
Since you can use rbw as an ssh-agent, it’s very convenient to use it for SSH keys. However, typing my long master password every time I push a local repository is inconvenient.
I’d like to let users configure a short (but still secure) PIN for convenience and security 1
We could even leverage the age plugin ecosystem so that the vault can be unlocked using a hardware key or macOS Touch ID via an age plugin.
Design
dek- master symmetric key which decrypts the contents of your vault. Held in memory by therbw-agentlocal_secret- 32-byte secret persisted via abackendbackend- either encrypt local_secret to disk withage(and bound to device via a plugin) or simply in the os keyring.PIN- arbitrary length user inputted stringkek- key derived fromPINandlocal_secretwith kdf (argon2id)wrapped_dek-dekwrapped with thekekpin_state- [wrapped_dek+nonce, salt+argon2params for derivingkek,backend] serialized to diskThe cli api will expose three commands
rbw pin setlocal_secretviabackend.PIN(with confirmation).dek→wrapped_dekand writespin_state.rbw pin statuspin_stateexists, and whichbackendis used (age / keyring).rbw pin clearpin_stateandlocal_secret.At
rbw unlock, we simply check that apin_stateexists in theactions::unlock_statefunction, ask for pin, decrypt and store the decrypteddekto the agent's state.Considerations
pin_state.backend(e.g keyring) is unlocked. Doesn't apply to hardware key style age plugins.dekinpin_stateand clear the pin if the rotated hash doesn't match.age-plugin-yubikey, we can allow them to use an empty pin for maximum convenience.Footnotes
A short pin / touchid on mac would make it painless to have a very short/instant locking time on the
rbw-agent, keeping thedekin memory for as short a time as possible. ↩