Frequently, I find myself needing to transfer files from my laptop or server, over to my personal phone or to other family-member’s devices. More than likely, I am unable to simply email or scp a file over to these devices. The files are usually just too large for email transfer. Thus, I have been working on a little rust API that accepts binary data, encrypts said data, then persists the metadata in a MongoDB replicaset, and the binary data in object storage.

The application I created is available at tackd.io, and is written in Rust. The code is hosted on Google Cloud Run, built via Continuous Deployment, utilizes Google Cloud Storage, and connects to an MongoDB Atlas replicaset in which to persist metadata.

How it works

Tackd is an encrypted message service API, which enables parties to anonymously and security transmit and receive data via a RESTful API.

Tackd encrypts payloads with the XChaCha20Poly1305 cipher upon receipt. Indexing data is then persisted in the backing MongoDB database, with the encrypted data stored in Cloud Storage. The encryption key is then returned to the sender, with the key not persisted by Tackd. Data retrieval is possible by any client with the required decryption key. Senders can also include an optional password, which is hashed by Tackd, and required for data retrieval.

When posting files, Tackd accepts a couple of TTL options for data expiration. Senders can either set a max number of reads for a file, or a max lifetime in seconds. The default TTL’s are one read, with a max lifetime of one hour. Max lifetimes are capped at one month, and if only the max lifetime if overridden by the sender, then max reads will be set to infinity, or -1.

These parameters are overridden with expires and reads query flags. Below are some scenarios when uploading files:

Sender Max Reads Sender Max Lifetime Tackd.io Max Reads Tackd.io Max Lifetime
N/A N/A 1 3600 seconds
10 N/A 10 3600 seconds
N/A 10000 -1 (inf) 10000 seconds
10 10000 10 10000 seconds

Data Encryption

Since tackd is deployed via lightweight containers, speed of decryption is of utter importance. Therefore, I decided to use the XChaCha20Poly1305 stream cipher to handle the encryption of data. This cipher is much faster than AES, and is simpler to implement, and costs less CPU. A random encryption key is generated when data is pushed to tackd, and is returned to the sender after the encrypted data has been persisted in storage. This key is not persisted by tackd.

Optionally, the sender can also include a required password to unlock the payload. The password is not persisted in plaintext, as only password hash is saved in the metadata database.

Tackd handles the encryption server-side, as the primary use case I imagined when building this service was to handle data uploads via curl, which doesn’t have client-side encryption capabilities. However, since tackd treats all data being uploaded as raw binary data, the data can simply be encrypted client side before upload to tackd. The client’s encryption key is then required for decryption, as well as tackd’s encryption key.

API Resources

Base URL

All API calls should be directed to either a locally running instance, or to the public https://tackd.io server.

Upload

Upload a file to Tackd.io

POST /upload

Path Parameters

None

Query Parameters
Attribute Type Requirement Notes
expires int optional Set data expiration time in seconds
reads int optional Set maximum number of reads for data
pwd string optional Lock data with additional password
filename string optional Specify filename for upload
Response Codes
Type Code Notes
Success 200 Returns json object
Error 500 Internal server error
Sample Response
{
  "message": "Saved",
  "url": "https://tackd.io/download/d2e1152b-ef91-4e4a-834c-62c41a4278e9?key=ldR9aQY5pBZThQtgsvb0YqK9xmerCBN0",
  "data": {
    "id": "d2e1152b-ef91-4e4a-834c-62c41a4278e9",
    "key": "ldR9aQY5pBZThQtgsvb0YqK9xmerCBN0",
    "expires in": 3600,
    "max reads": 1
  }
}

File Retrieval

Download a file from Tackd.io

GET /download/{id}

Path Parameters
Attribute Type Requirement Notes
id string required Specify data id or file to download
Query Parameters
Attribute Type Requirement Notes
id string optional ID to get, use if filename is passed in path
key string required Decryption key
pwd string optional Unlock data with password
Response Codes
Type Code Notes
Success 200 Returns binary data
Error 401 Not Found
Error 500 Internal server error