Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


hushfile is a file sharing service with clientside encryption. Idea and initial code by Thomas Steen Rasmussen / Tykling, 2013.

This code is released under 2-clause BSD license, so you are free to use this code to run your own hushfile service, modify the code, or whatever you like.

Theory of Operation

The hushfile server is pretty simple, most of the hard work is done by the clients. The server basically takes requests and replies with HTTP status codes and json blobs. The server has an upload function which returns a fileid, the rest of the operations require an existing fileid.

The following describes the client workflow. The details are probably only relevant if you are curious or if you are implementing a new client.

A client has two basic jobs: uploading and downloading. This section describes how a client operates, based on the hushfile/hushfile-web client. If you are implementing a new client read the API file for details.


0. Call serverinfo API function

Initialize client by calling the serverinfo API function to display the servers max file size (if any) and max retention time (if any) to the user.

1. Pick file

A file is selected by the user.

2. Check max file size

The client must check the file size against the maxsize value returned by the serverinfo API function, and display an error if it is too large.

3. Decide on chunking

The client should decide whether or not to use chunking, and a chunksize. The serverinfo API function returns a maxchunksize value which should be taken into consideration.

4. Generate passwords

The client must generate an encryption password. If the user wants the file to be deletable a deletepassword should also be generated. It should be possible but difficult for a user to choose custom passwords. Long automatically generated alphanumeric password are the most secure.

5. Generate metadata json

The client must generate a json object containing four fields if the file should be deletable: {"filename": "secretfile.txt", "mimetype": "text/plain", "filesize": "532", "deletepassword": "vK36ocTGHaz8OYcjHX5voD8j3MgsGkg8JAXAefqe"} If the file should not be deletable the deletepassword field should be omitted.

6. Encrypt metadata json

The client must encrypt the metadata json with the encryption password.

7. Encrypt first file chunk

The client must encrypt the first chunk of the file. If the servers permitted chunksize and the clients desired chunksize are both equal to or larger than than the total filesize there will only be one chunk.

8. Upload first chunk and metadata

The client must do a HTTP post to https://servername/api/upload with five fields: cryptofile, metadata, deletepassword, chunknumber and finishupload. The number of the first chunk is 0. The finishupload field must be set to true if this is the only chunk, and false if there are additional chunks. The metadata must be uploaded with the first chunk.

9. Receive response with fileid and uploadpassword

The client will get a HTTP 200 response with a JSON body which contains six fields: {"fileid": "51928de7aba77", "status": "OK", "chunks": "1", "totalsize": "12345", "finished": false, "uploadpassword": "abc123DEF456"}

If the upload is finished uploadpassword will be empty, otherwise it contains the password neccesary to upload new chunks.

10. Encrypt and upload remaining chunks

If any chunks remain the client must encrypt and upload each one with a HTTP post to https://servername/api/upload with five fields: fileid, cryptofile, chunknumber, uploadpassword and finishupload. This can be done in parallel if desired.

When the last chunk is uploaded the finishupload field should be set to true, or the upload can be marked as finished by using the seperate finishupload API call.

For each chunk uploaded successfully the client will get a HTTP 200 response with a JSON body like this: {"fileid": "51928de7aba77", "status": "OK", "chunks": "3", "totalsize": "1234567", "finished": false}

11. Present link to the user

The client must finally present a link to the user, in the format https://servername/fileid#password


1. Get hushfile URL

A hushfile URL is supplied by the user

2. Check URL and fileid validity

The client checks if the fileid is a valid and finished upload on the server, by querying https://servername/api/exists?fileid=51928de7aba77

3. If fileid is valid

If the fileid is valid and the upload is finished the server will reply with a HTTP 200 with a JSON body like so: {"fileid": "51928de7aba77", "exists": true, "chunks": 2, "totalsize": 123432, "finished": true}

4. If fileid is valid but unfinished

If the fileid is valid but the upload has not been finished the server will reply with a "HTTP 412 Precondition Failed" with a JSON body like so: {"fileid": "51928de7aba77", "exists": true, "chunks": 2, "totalsize": 123432, "finished": false}

5. If fileid is invalid

If the fileid is invalid the server will reply with a HTTP 404 with a JSON body like so: {"fileid": "51928de7aba77", "exists": false, "chunks": 0, "totalsize": 0, "finished": false}

6. If password is missing

If a password was not supplied, the client must ask the user for a password.

7. Download metadata

The client must then download the metadata from the server by querying https://servername/api/metadata?fileid=51928de7aba77

8. Decrypt metadata

The client must then decrypt the metadata using the supplied password.

9. If decrypt fails

If the data cannot be decrypted or the decrypted data is not valid JSON, the client must display an error to the user and ask for a new password, and try decrypting again.

10. Metadata json

The decrypted JSON metadata contains four fields and could look like this: {"filename": "secretfile.txt", "mimetype": "text/plain", "filesize": "532", "deletepassword": "vK36ocTGHaz8OYcjHX5voD8j3MgsGkg8JAXAefqe"}

11. Get uploader IP

The client must now get the IP address of the uploader by sending a request to https://servername/api/ip?fileid=51928de7aba77

12. Present download and delete options to user

The client must present the metadata and IP to the user, and give the user two options, download and delete.

13. To delete file

If the user wants to delete the file, the client can do that by sending a request to https://servername/api/delete?fileid=51928de7aba77&deletepassword=vK36ocTGHaz8OYcjHX5voD8j3MgsGkg8JAXAefqe.

If the deletion is successful the server responds with a HTTP 200 and a JSON object like this: {"fileid": "51928de7aba77", "deleted": true}

If the deletion fails because the deletepassword is incorrect, the server responds with a HTTP 401 and a JSON object like this: {"fileid": "51928de7aba77", "deleted": false}

14. To download a chunk

If the client wants to download the file, the client can get the data for a given chunk by sending a request to https://servername/api/file?fileid=51928de7aba77&chunknumber=N - if there is only one chunk the number is 0

15. Decrypt downloaded data

The client must then decrypt the file with the same password as the metadata was decrypted with.

16. Repeat for every chunk

Repeat for every chunk, put the chunks together when all of them are downloaded.

17. Prompt user to save file

Finally the client can prompt the user to save the file somewhere.

18. Delete option

The client should still have an active delete button after download, so a user can delete a file after downloading.

3rd Party Components

The following components are used extensively in the code:


Main hushfile repo with documentation etc.






No releases published


No packages published