Himitsu is a WORK IN PROGRESS system for storing secrets.
Himitsu stores an encrypted list of records, each of which is a list of keys and values, some of which may be secret. Records are represented in a format inspired by Plan 9's ndb and factotum, and the same format is used both for representing records, querying for records, providing templates for incomplete records (which the user is expected to fill in), and so on.
The format of a record is a space-separated list of key/value pairs. Here's an example record with IRC credentials:
proto=irc host=irc.freenode.net nick=ddevault password!=hunter2
Single-quotes can be used to add spaces, and two single-quotes to escape a single-quote inline:
proto=example 'my key'='my value' myquote='a single -> '' <- quote'
Note that additional information beyond the password (such as the protocol, host, and nickname) are stored by Himitsu as well. The bang (!) indicates that the password field is a secret. In some contexts, it may be omitted for this reason, resulting in the following:
proto=irc host=irc.freenode.net nick=ddevault password!
This indicates that a password is expected, but is omitted in this context. Say that you'd like to implement an IRC client. You can connect to the RPC socket and query for all IRC credentials:
-> query proto=irc <- key proto=irc host=irc.freenode.net nick=ddevault password! <- key proto=irc host=chat.rizon.net nick=sircmpwn password! <- key proto=irc host=example.org port=1337 nick=sircmpwn password! <- end
If you'd like to read the passwords, you'd use the lookup command:
-> lookup proto=irc <- key proto=irc host=irc.freenode.net nick=ddevault password!=hunter2 <- key proto=irc host=chat.rizon.net nick=sircmpwn password!=hunter2 <- key proto=irc host=example.org port=1337 nick=sircmpwn password!=hunter2 <- end
There'd be a delay between "lookup" command and the list of keys while the user is prompted for consent. Then, let's say that the user asks you to configure a new IRC network. You can issue the following command:
-> add proto=irc host port? nick password!
The user will be shown another prompt and asked to fill in the extra details, optionally generating a password. The question mark (?) for the port parameter indicates that it's optional; the user may choose to omit it. You can use optional and required parameters in your query, by the way, something like this:
-> query proto=irc host port? nick password!
This would only return results which have everything you need. Anyway, after the user fills out the new network details, it's returned back to you:
<- key proto=irc host=irc.freenode.net nick=ddevault password!=hunter2
And you can go ahead and establish the connection.
But wait! In this scenario, you're directly handling the user's credentials, and that's kind of shit. Let's instead do the following:
-> agent proto=irc <- transfer proto=irc host=irc.freenode.net nick=ddevault password! <- transfer proto=irc host=chat.rizon.net nick=ddevault password! <- transfer proto=irc host=example.org port=1337 nick=ddevault password! <- end
The agent command understands common protocols. In this example, the user is
prompted to consent, then the daemon launches a special
(or rather, any
hiagent-$proto command) and passes it the user's cleartext
password, as well as your Unix socket connection. The agent command connects to
IRC and negotiates authentication with the remote server, and each
command returns a file descriptor to you in the Unix domain auxillary data which
represents the established connection. Your IRC client takes the file descriptor
and assumes control over the connection, and you've successfully connected to
IRC without ever seeing the user's password.