Overview
keys is designed to provide secure centralized storage of sensitive
information such as authentication credentials. Keys stores this
information in individual encrypted files called entries, and also
stores an index of all entries in an encrypted index file.
The security of keys is dependent on the clients and server running
on trusted devices that provide secure execution and storage. keys
does not assume the local network is trusted.
Assuming uncompromised devices, keys should provide the following
security features:
1. An attacker who obtains the database files cannot decrypt the
index or entries, or distinguish one entry file from another
of similar size (but see Filesystem Metadata).
2. An attacker on the local network can discover the server and
record client/server traffic but cannot decrypt it.
3. An attacker on the local network cannot impersonate the
server without obtaining the server's private key.
4. An attacker on the local network who obtains the server's
private key cannot decrypt any previous network traffic.
5. An attacker on the local network who obtains a client's
private key but not the database password can only learn
the database KDF parameters.
Less formally, once the client or server are compromised any
further use of keys will void all security expectations. However
the system should remain secure until such use occurs.
Storage Security
A keys database consists of entry files, each containing a number
of key/value fields, and a single index file containing an index of
all entries, the database key, and scrypt KDF parameters.
Each entry file has a randomly generated name which is created by
base64-encoding 16 bytes of output from a CSPRNG. These files are
encrypted with AES256-GCM(k0, XSalsa20Poly1305(k1, ...)) using the
database key which is randomly generated during database
initialization or rekeying.
The index file contains the database key, entry index, and KDF
parameters. The entry index is encrypted using the database key, and
the database key itself is encrypted with a KEK generated by
applying the scrypt KDF to a user-supplied password and the KDF
parameters. Both the document index and database key are encrypted
with AES256-GCM(k0, XSalsa20Poly1305(k1, ...)).
Additionally a keys database may be backed up into a single export
file. The export file contains KDF parameters and a set of encrypted
entries. Each entry is encrypted with the same cascading encryption
scheme: AES256-GCM(k0, XSalsa20Poly1305(k1, ...)) using a key which
is generated by applying the scrypt KDF to an export password.
Network Security
Clients communicate with the server using TLS 1.2 with a single
allowed cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384. The
server and client are mutually authenticated with X.509 certificates
containing NIST P-384 EC keypairs generated on the server device.
Clients locate the server using a link-local IPv6 multicast ping
packet containing a random nonce. The server responds with a pong
containing the nonce and the address and port it is listening on.
Valid pongs are signed by the server's public key and the nonce and
signature are verified by the client.
Filesystem Metadata
Entry and index files are assumed to be stored on a filesystem that
maintains metadata about each file including timestamps, size, etc.
keys attempts to minimize the amount of information this metadata
leaks.
Each time an authorized client request is processed the last access
and modification times all entry files and the index file are
updated to an identical value of the current time.
Each entry and index file is padded to an even multiple of 1024
bytes to partially obscure the size of the content. Entries are
expected, but not required, to be less than 1024 bytes. Entries
larger than 1024 bytes will be distinguishable from others.
Cryptography
NaCl and OpenSSL are used for all cryptography and OpenSSL provides
the TLS implementation. All encryption is done using a cascade of
AES256-GCM(k0, XSalsa20Poly1305(k1, ...)). OpenSSL provides the
AES256-GCM implementation and XSalsa20 + Poly1305 is NaCl's
secretbox function.
IVs used for the database key, index, and each entry are randomly
generated via NaCl's randombytes() function which also generates the
64 byte (512 bit) database key.
Weaknesses
1. The keys code is has never been reviewed by a 3rd party and is
written in the C language which provides very little safety and
many opportunities for critical mistakes.
2. Compromise of the server's private key allows an attacker to
impersonate the user's server, retrieve the KEK which encrypts
the database key and thus all data, and break all security
guarantees from that point forward.
3. Compromise of the client's private key allows an attacker to
communicate with the server, receive the scrypt KDF parameters
used to encrypt the database key, and mount a remote brute-force
attack on the database or denial-of-service on the server.
4. Modern filesystems and flash storage may store data in multiple
locations and not actually perform deletions until a later
date. Copies of some or all of the encrypted database at
different ponts in time may be retrievable by an attacker.
5. Filesystems store a variety of metadata containing the time a
file was last accessed, modified, changed, etc. Keys attempts to
obscure this but an attacker may still be able to learn something
about an entry based on the time it was last accessed or
modified.
6. Entry and index files are padded but will still leak information
about the real size of the data when it is larger than the
padding size. This will also allow larger entries to be
distinguished from others.
7. Operating system and library functions may persist copies of
keys, entries, or the index that could be accessed by an attacker
who can copy the client or server's RAM.
8. An attacker on the local network can conduct a denial-of-service
attack against both the client and server.