Tackd - Anonymous File Transfer

· 4min · Dan F.

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 ReadsSender Max LifetimeTackd.io Max ReadsTackd.io Max Lifetime
N/AN/A13600 seconds
10N/A103600 seconds
N/A10000-1 (inf)10000 seconds
10100001010000 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

AttributeTypeRequirementNotes
expiresintoptionalSet data expiration time in seconds
readsintoptionalSet maximum number of reads for data
pwdstringoptionalLock data with additional password
filenamestringoptionalSpecify filename for upload

Response Codes

TypeCodeNotes
Success200Returns json object
Error500Internal 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

AttributeTypeRequirementNotes
idstringrequiredSpecify data id or file to download

Query Parameters

AttributeTypeRequirementNotes
idstringoptionalID to get, use if filename is passed in path
keystringrequiredDecryption key
pwdstringoptionalUnlock data with password

Response Codes

TypeCodeNotes
Success200Returns binary data
Error401Not Found
Error500Internal server error