# Is there something like a secure hashmap?

TL;DR: Is there such a thing as a hashmap whose contents cannot be read unless you have the right encryption key, and where each encryption key only works for a specific key value pair?

More context:

Say you're building an offline first web application and want to save the client from having to do a bunch of round trips to the server to ask for data. Within such constraints you may decide to, say, provide a whole dump of the database when the client first loads the site, and then the client can query its own copy of the database without needing to talk to the server.

You wouldn't want sensitive data to be part of the database dump, so you're not going to include user emails and passwords in the dump. But here you run into a problem: part of the website relies on user data (perhaps a user wants to view another user's profile) and would then need to query the server.

Given that we want to avoid any additional requests from the client to the server beyond the initial request for the db dump, how could this be achieved? Let's assume you wouldn't include emails and passwords in the dump, but user data that is publicly available, such as user handles and full names.

In such a case, you could simply include user handles and full names in the db dump in plain text. But you don't want to do that because it would give away all users' names at once, as well as metadata such as how many users your site has, etc. If a user reads some other user's handle and name by browsing your site, that's one thing - but if he can read all users at once, that's a problem.

So I'm wondering if part of the dump that contains user data could be made of a sort of "secure hashmap". What I mean is that its contents are not readable unless you have the right key; and even then only those contents that correspond to the key can be read.

If there isn't, I would imagine its implementation to go something like the following:

It works like a regular hashmap, with the exception that all its keys are hashed, and its values are encrypted. That way, even though the consumer could iterate over all keys and values, he wouldn't be able to do anything with them. When a piece of privileged information that acts as a key into the hashmap is made available to the consumer - say, a user handle - the lookup mechanism could first hash the user handle, use the result as a key to the hashmap, and then the user handle would allow him to decrypt the corresponding value (e.g. the full name corresponding to that user handle). The producer creates the hashmap by hashing its keys and encrypting its values by partly using their keys.

So in short, if the producer has a hashmap that contains:

"foo" => "bar"


He then turns it into

"1234" => "6%!*3"


where "1234" is the result of hashing "foo", and "6%!*3" is the encryption of "bar" using "foo" as encryption key (or something along those lines, I'm afraid I don't know much about encryption - what I mean is that it should be possible to use the string "foo" to decrypt "6%!*3").

Am I trying to reinvent the wheel here? If not, is the implementation I'm proposing secure?

Edit: I just realized that doing it the way I proposed above would still divulge the number of entries in the hashmap. Ideally, that could be avoided, too.

• It sounds like you need to query the server for the appropriate decryption key each time you want to look up a new handle? Unless all decryption keys are bundled eith the encrypted map. – Geir Jan 14 at 5:30
• I don't think so. If the encryption key is the user handle itself, then it could just be provided as part of a URL, e.g. /users/username. – weltschmerz Jan 14 at 6:15
• Or: the encryption keys can be part of the initial db dump. They may appear as data in other db entries. E.g. a dump of posts and each post has the author's user handle. – weltschmerz Jan 14 at 6:26
• If there's something the client can do to access a user's data, offline, what stops them from doing it for all users? If there's nothing they can do to access a user's data, then why send it? – user253751 Jan 14 at 12:19
• Nothing stops them. I realize now that this is more about obfuscation than security, and therefore isn't secure at all. – weltschmerz Jan 14 at 18:50

where "1234" is the result of hashing "foo", and "6%!*3" is the encryption of "bar" using "foo" as encryption key (or something along those lines, I'm afraid I don't know much about encryption - what I mean is that it should be possible to use the string "foo" to decrypt "6%!*3").

So you want to encrypt the usernames, then use the username as an encryption key to the email address and other data?

This is doable and not difficult. If your usernames are unique, you can run the username through a PBKDF to generate a symmetric encryption key, then use it to encrypt the rest of the user's data. If they are non-unique, you need to concatenate the username with a salt first (a piece of non-secure data such as UserID).

My primary concern would rather be with whether the username can be used as a secret. If there is a public user profile, it can be trivially easy to obtain the complete list of usernames by querying the server for users with ?id=1, ?id=2, and so on. Many web applications, e.g. forums, outright offer a complete list of users.

Even if the username serves as a log-in only, and not for sharing anything, it's common practice to use the same username across multiple websites. Just trying each out of a few million usernames grabbed from various sites on the web, which don't make a secret out of them, could probably give one access to about half your entries. Large username dumps are publicly available.

It would be best to find something that is not publicly available to use as the encryption key. Unfortunately, mass dumps or email addresses are also readily available on the web.

Hash is a one way function: Given the word "password" you can hash it to "1ks9237&#lsdfsdfukd&lnadflaoewukidsgfb*#", but given the hash, you cannot get the original word "password". The hash has a fixed size, not related to the input (the words "password" and the phrase " I have a password" will produce the same size hash).

Schema: