Building a share feature with privacy in mind

One of the main reason for me to build Padlok was data management. I didn’t want anyone to retrieve my friends addresses and codes. As with any contact related infos, I may have trust issues about them.

And so should you!

That’s also why Padlok development is focused around data privacy and security. Data is stored on device only, an synced with iCloud. And early share feature was simply generating a small text to be shared. But this experience was not enough.

Padlok app icon

Padlok

Still looking for the codes?

Learn more

iOS share experience features

Apple came up with a lot of share experience features within the last years.

Universal Links opens a link directly in the application for a full native experience when it’s installed on device.

App Clips transforms a simple link share experience to a full native experience, and maybe can make someone to download the full app.

Finally, a link is a link, and can open the shared infos within a webapp when all of the above is not available (older OS, or any non-iOS device). Plus Smart banners might redirect users to the App Store when the above experience failed on iOS.

The conclusion is clear: sharing a link, with the above experience changers are a must have for a modern iOS app.

First problem is that link are public. And without any authentication service, anyone with the link could access the data. The solution here is to generate hard to guess links.

Links will have the form https://share.padlok.app/<hard to guess ID>/<hard to guess KEY>

Updated on December 4, 2022
After a comment made by Valtteri Huuskonen, links were updated to format like: https://share.padlok.app/<hard to guess ID>#<hard to guess KEY>
Thanks to that, the key, that is our secret, is never sent to server, because it’s now using URI fragments.

Next problem is that some might try to guess urls anyway. So we need to have a restriction mechanism that would detect and prevent url iteration to be possible in reasonable time.

API that serve data will have a limit to prevent a single user to make too many fetch attempts.

Then, by default, urls are logged and stored on the webserver itself. And I don’t want to possess any share url what-so-ever. So I decided that for the shares urls, logs should be disabled.

location / {
  access_log off;
  (...)
}

Updated on December 4, 2022
Even if the new link format prevent key leaks, logs are still disabled to be sure that older links do not leak links!

The final problem is about data. I do not want to possess any user data on my server. But somehow, I have to, since all the data cannot be stored in the URL.

End-to-end encryption for data

Modern encryption result is indistinguishable from noise. And it’s exactly the kind of data I expect to store on my server, associated to a generated identifier. And to make sure the process is completely secure, I don’t want to store the key material. Key material will be in the url itself, that, for recall, will not be logged.

Finally, the key will never be managed by my server. I want to make encryption end-to-end.

Since I wanted the encryption an decryption to happen either on the iOS app, or from the webapp client side (a.k.a in JavaScript), using a cryptographic standard that’ll be easier to set up.

AES-GCM will be the encryption algorithm here. With a shared key of 256 bytes; this encryption method is one of the widely adopted for its performance and confidentiality.

So we need to share a 256 bytes key in the URL. A way to do that would be to have the key as is in the URL, encoded in a base62 or base64-like format. But in that format, the key takes up to 44 characters. It’s a bit long.

To reduce the URL size, we need to reduce the entropy of the key. I decided to do so using PBKDF2 key derivation.

The input for generating the key is now up to three variables:

VariableOriginStorage
passphrase Generated stringProvided in the URL
nounceGenerated dataWith cyphered data on the server
iteration countGenerated numberWith cyphered data on the server

And from those, we can now generate the key

The final process

Encryption

We start to generate the key parameters:

Before making the key:

Passphrase + Nounce + Iterations -> Key

Then use that key for encryption:

And perform the encryption:

Data + IV + Key -> AES-GCM -> Cypher

And we store on the server:

Decryption

For the decryption, we retrieve from the server the data described above, and we use the passphrase from the URL:

We can then make the key again:

Passphrase + Nounce + Iterations -> PBKDF2 -> Key

And then decrypt the data:

Cypher + IV + Key -> AES-GCM -> Decrypted data.

Open-Source implementation

Most of the implementation for Padlok Share feature is Open-Source on my Github:

Making all of this code open-source is for me a natural decision of both transparency, and security. Transparency because anyone can check that I actually do what I describe within my codebase; and security because having other minds to challenge my implementation can help to resolve possible issues in security.

Padlok app icon

Padlok

Still looking for the codes?

Learn more

Don’t miss a thing!

Don't miss any of my indie dev stories, app updates, or upcoming creations!
Stay in the loop and be the first to experience my apps, betas and stories of my indie journey.

Thank you for registering!
You’ll retrieve all of my latest news!

Your email is sadly invalid.
Can you try again?

An error occurred while registering.
Please try again