Secrets was designed to be secure from the start. That means using standard and strong encryption algorithms and having every feature designed with end to end encryption in mind. This page details how Secrets stores and handles your data but if you just want a quick summary:
Secrets uses the Sodium library for most of its cryptographic functions. Specifically, it uses Argon2 as password based key derivation function that’s fed with your passphrase to generate the key used to protect the main key. The main key is then used to encrypt your store file using XChaCha20+Poly1305 authenticated encryption. The store file will also contain randomly generated keys to protect any attached files.
Each section starts with an overview of the feature and dives into the nitty gritty details whenever appropriate.
- Storage format
- iCloud Sync
- Secrets Helper (Mac)
- Browser Extensions (Mac)
- iOS Extensions (iOS)
- Remote Access (iOS)
Your passphrase is the key to your data. Without it there’s no way to access your secrets1. To put it simply, the security of your data is tied to the security of your passphrase. So it’s important to understand that choosing a long and memorable passphrase is crucial.
All features in Secrets use securely generated keys and modern encryption algorithms but you still need to pick a good passphrase.
Secret’s on disk file format is actually composed of many different components bundled together in what’s called a “file package”.
A file package perceived by the user as a single file but it’s actually a directory containing files and possibly other directories.
Secrets.secrets ├── key ① ├── keys ② ├── store ③ ├── index ④ └── files/ ⓹
On the first run, when creating your data store, Secrets will securely generate a 256 bit key which will be used to protect your data. Let’s call it the “main key”. The main key itself is protected by your passphrase.
Your passphrase is fed into the Argon2 key derivation function to generate a key suitable to use for encryption. The generated key is then used to encrypt your main key using the XSalsa20 cipher and the Poly1305 MAC. The result is stored in the
Specifically, Secrets uses the
crypto_secretbox_* functions from the Sodium library for key derivation and encryption respectively.
keys, also called a keyring, stores a series of OpenPGP public keys that the user has trusted. This is reserved for future features and is currently not in use.
This is where your items are stored. It’s actually a TAR file composed of a few different files:
$ tar -tf Secrets.secrets/store metadata secrets nonce mac
metadata file is in plain text and contains information such as the store id and model version. The
metadata file is an
NSKeyedArchiver file and can be extracted with the
$ tar -xvf Secrets.secrets/store metadata x metadata $ ~/bin/PlistExplorer metadata NSPersistenceFrameworkVersion 866 NSStoreModelVersionHashes BankAccount NSData with: 32 Bytes Credential NSData with: 32 Bytes (...) // redacted for brevity Tag NSData with: 32 Bytes NSStoreModelVersionHashesVersion 3 NSStoreModelVersionIdentifiers NSStoreType SDMAtomicStore NSStoreUUID E5EBD1DE-C4DB-4015-8D69-B5ED49CD1E50 lastReferenceObject 1260 sbx_identifier 2A544A[email protected]
secrets file is where your items are stored. It’s encrypted with your main key using the XChaCha20 cipher and the Poly1305 MAC. The
mac files are related to the
secrets file encryption and contain the nonce and authentication tag respectively.
Internally, Secrets uses the
crypto_aead_xchacha20poly1305_ietf_* functions from the Sodium library in detached mode. Using authenticated encryption with associated data (AEAD) allows the
metadata contents to also be authenticated alongside your items.
Each item the user saves in the
store file contains an identifier. The
index file maps words used on those items to the respective identifiers. This is then used to perform fuzzy searching.
index file is encrypted with a key derived from your main key using the the XSalsa20 cipher and the Poly1305 MAC.
To derive the encryption key Secrets uses the
crypto_kdf_derive_from_key function from the Sodium library, and encryption is done with the
crypto_secretbox_* functions from the same library.
files/ directory contains any attachments you may have added to your items, including custom icons.
For each file attached, Secrets will generate a new 256 bit key and save it, along with some metadata about the file, in your store file. The contents of the file itself will be saved in this folder using the XChaCha20 cipher and Poly1305 MAC. The filename is randomly generated.
Internally Secrets uses the
crypto_secretstream_xchacha20poly1305_* functions from the Sodium library.
When syncing via iCloud a new data store is created behind the scenes. This store format is the same as your main store except there’s no
index file. This data store’s main key file is also protected with a key based on your passphrase. Hence the need to have the same passphrase on all your devices.
The data store itself is then uploaded to iCloud using the CloudKit APIs. When syncing with iCloud, Secrets will pull all the changes from iCloud, unlock the data store and synchronize the changes with your main store.
Because it’s an independent data store, you can disable and delete the iCloud data store at any time and keep the data you have locally on your device.
Secrets Helper (Mac)
On the Mac, the Secrets Helper is a small utility app that Secrets starts automatically on launch. It’s purpose is to facilitate a few different features on the Mac:
- Displaying an easily accessible icon on the menubar
- Observing the running applications to offer shortcuts to actions in Secrets
- Serve as a bridge for Browser Extensions
The Secrets Helper never accesses your data directly, nor does it ever ask you or handle your passphrase. It communicates with the main application via a unix socket. Communications between the browser extensions and the Secrets app are encrypted with the Noise Protocol using our open source wrapper for Noise-C.
More precisely, the
NoisePSK_NN_25519_ChaChaPoly_SHA256 handshake format is used with a pre-shared key being generated by the main app and stored in the system keychain.
Browser Extensions (Mac)
Similarly to the Secrets Helper, the browser extensions also never access your data directly. They serve two main purposes:
- Informing the Secrets Helper of fillable forms
- Performing a fill at the command of the user
The extensions use Native Messaging to communicate with the Secrets Helper. More precisely, the extension code issues and receives commands to the browser launched executable included in Secrets. This communication is done simply via standard input and output. The executable itself then communicates with the Secrets Helper using another unix socket. Just like the communication between the main application and the helper, the browser extensions also use the Noise Protocol for encryption.
On Windows and other platforms the browser extensions can also remotely request secrets from Secrets for iOS. See Remote Access.
iOS Extensions (iOS)
To allow for a better integration with operating system, iOS allows apps to include some extensions that itself will launch on behalf of the user. By design these extensions are not the same as your main app. Secrets includes extensions for Siri, Password AutoFill, Share and potentially others as iOS evolves.
Unlike the Mac, there’s no communication between the extensions and the main app. So they all must read/write to a shared container where your data is stored. Although technically these are different apps, they share the same code with the main app. And for the most part they’ll look and feel like the same app to you.
Remote Access (iOS)
Starting with version 3.4.0, Secrets for iOS can also be used as a remote keychain. Similarly to how the browser extensions request secrets from a locally running instance of Secrets for Mac, remote requests also use the Noise protocol (with
Noise_KK_25519_ChaChaPoly_SHA256) to establish a secure end-to-end encrypted connection with Secrets for iOS. A WebSocket server in our control is used to bridge the two devices. Note however this server is stateless, it doesn’t know anything about each of the connecting parties.
Here’s a brief overview on how a request is sent:
- The browser extension connects to the WebSocket server and is assigned a random id.
- The extension then sends a push notification to the device stating the user is requesting a secrets and the extensions is connected with the random id assigned on step 1.
- After tapping the notification, Secrets for iOS also connects to the WebSocket server, gets its own random id, and establishes a secure connection with the extension. The WebSocket server knows where to route these messages because of these ids.
Secrets 3.6.0 introduced Ad Hoc requests with the goal of making it easier to do one-time requests on shared computers. These type of requests exchange the pairing phase with showing a QR code for every request.
- Secrets for Mac has the ability to create a recovery key in case you ever forget your passphrase. [return]