Security And Cryptography
Security and Cryptography¶
Security brief¶
When building the Space Daemon, our number one priority was ensuring everything is private and secure. There are many security layers stacked onto each other in order to make it secure from the moment a key is created to the one a file is shared.
In this section we detail the security measures taken in each of the following steps:
- Account key generation and storage
- Key backups
- File sharing encryption
- App runtime security
Account key generation and storage¶
A user account in Space is really just a Private Key. Specifically, we currently use the Ed25519 encryption algorithm for our user keys. We generate them using BIP39 in order to also generate a mnemonic code that maps to this key in order to recover it later on.
To store this key, we use OS-level keychains whenever they are available. That way keys inherit the same level of access control:
- In MacOS we use the default Keychain app
- In Linux/Ubuntu we use pass
- In Windows we use the Windows Credential Store
Key backups¶
Applications using the Space Daemon can choose to use our backup services by calling the BackupKeysByPassphrase and RecoverKeysByPassphrase methods. Key backups are extremely important if you want to allow users to sign in on multiple devices or to be able to clear their local storage and be able to still see their files later on.
To enable this service, Space Daemon connects to a cloud API called Space Services (you can read the code by clicking here). Specifically, we use the vault service in Space Services. A vault is used to securely store user private keys based on a master password. It is hosted on the cloud and uses the cryptography described in the following section to assure no one without the password can access the data directly, and that no one can brute-force the passwords either. It works very similarly to password managers.
Storing private keys¶
The client needs to complete a challenge to prove they have access to a given public key. Once they have proven access, the server allows replacing the vault file for a new one.
Private key signing challenge flow:
- Client sends to the server their public key
- Server issues a challenge
- Client signs the challenge using its private key
- Server verifies signature matches the public key, returning a JSON Web Token (JWT)
Storing the private key:
- Client creates the vault file (
vf
), which is a JSON document that maps public keys to their private keys, but can also contain anything we want to store. - Client computes its vault key (
vk
). To do this, it runsPBKDF2(password, salt, iterations, hashingFn)
, wherepassword
is the master password,salt
is the user'suuid
,iterations
is a high number to prevent brute force (set to 100.000 as of now), andhashingFn
is SHA512 which is the industry standard for a secure hashing function. - Using
vk
, client encryptsvf
using AES, obtainingvk(vf)
. - Client computes the vault service key (
vsk
) by doing key derivation again:PBKDF2(vk, password, iterations, hashingFn)
, wherepassword
is the master password. - Client submits
vk(vf)
,vsk
and the JWT back to the server. - Server verifies the JWT and successfully stores
vk(vf)
for the user with the given uuid. - Server stores
vskHash = PBKDF2(vsk, iterations, hashingFn)
using a really high value foriterations
.
Retrieving the private key¶
- Client computes
vk
andvsk
again as in step (2) and (4) of the previous section. - Client sends a retrieve request to the server with
vsk
anduuid
as the params. - Server computes
vskHash
as in (7) of the previous section. - Server checks
vskHash
matches the one stored. If it does, it returnsvk(vf)
. If not, returns a "Wrong password" error. - Client decrypts
vk(vf)
usingvk
, obtainingvf
back and getting access to its private keys.
Takeaways¶
- The client only needs to remember the master password and the uuid (which is obtained through a username, so it needs to remember the username).
- The server only receives
vsk
and therefore cannot decryptvk(vf)
from it alone. It can bruteforcevsk
to obtainvk
, but givenvk
is a SHA512 hash already, it'd take a billion years. - If a middleman intercepts the client->server message, and somehow gets to decrypt the first layer of protection which is TLS, it can't decrypt
vk(vf)
withoutvk
. - The server should implement rate-limitting to protect weak master passwords from being cracked.
File sharing encryption¶
Most of the privacy and encryption problems of file sharing are already taken care of by Textile. We use Textile's Private Buckets. You can get a deep dive on Private Buckets on Textile docs by following this link, but in summary, all files are encrypted on the way in and decrypted on the way out using AES. Bucket metadata is stored on Textile Threads which handle encryption-based access control by default.
On top of this, in order to double ensure our file backup servers are not reading your data, the Space Daemon encrypts each file using AES too, and sends the encrypted file to Textile APIs. Space Daemon stores the encryption key of each file in a Textile thread which only lives on the local computer (the rest of the threads live remotely in order to enable file sharing). This key-storing thread is replicated on the cloud in case we need to restore it on a new device, but the Thread Key
never leaves your local computer. Thread contents are indecipherable without it.
App runtime security¶
So far, we are making sure that keys are safely stored locally, safely backed up with near zero probabilistic chance of getting brute-forced (in case our databases got leaked), and files are being shared back and forth with strong cryptographic guarantees. However, the Space Daemon has open ports and another app running on the local machine could call its gRPC endpoints to execute unasked operations. To prevent this, the Space Daemon uses app tokens to gateway access to its gRPC interface. The first time the Space Daemon is initialized, it will allow calling the InitializeMasterAppToken method. This will generate a token which needs to be sent on each subsequent call to the Daemon. If the Daemon detects this token, it will allow access to any of its endpoints.
If the Space Daemon is already initialized, you can call the GenerateAppToken
method, which receives an array of allowed methods that this token is going to have scoped access to. In an upcoming release of our Space App, we will be offering a marketplace of Space compatible third-party apps. The user will be able to selectively authorize the generation of app tokens ("Do you want to allow 'App X' to read your files?") so that these third-party apps can for example access the files of a user and offer new services on top of them.