# Toy one-way hash function for six digit number

I need to copy some data from a secure server to my laptop to work on it with a program (this description is very vague, I know). The data have six digit employee numbers and we are strictly prohibited from downloading data with these.

I was wondering if there is a really simple hash function I could put in a spreadsheet to convert these employee numbers into a one way hash so I can download these? All I care about is being able to tell which data came from the same employee number. I am not terribly concerned about a few collisions either, the set is small enough I could look for those.

I was thinking some simple xor with an added salt or squaring and taking some digits but everything seems like it would be too guessable especially if there is a series of sequential employee numbers in a row.

For example, hash

123456


to somerandomlookingstring, but I need to be sure the next result is

123457


is not terribly similar, so not like: somerandomlookingstrifh

I feel like this is something hardcore crypto people may know off-hand, some mini ancestor of MD5, some evolution of ROT13, but light enough for thousands of spreadsheet cells.

• light enough for thousands of spreadsheet cells - have you actually tested just using SHA256/SHA512? It is entirely possible (if not even probable) that the perceived performance problem is not actually a problem. – Ella Rose Jul 9 '19 at 20:48
• My spreadsheet program didn't seem to have any built in hash functions. Maybe I am missing them. – Gordon Burgess Jul 9 '19 at 20:51
• AFAIK This won't work anyway since brute forcing even "real" hash functions like the SHA functions would take much less than a second for all of the 1 million employee numbers together. You would need something like PBKDF2 with a high iteration-count for any chance of keeping the id numbers secure. – ispiro Jul 9 '19 at 21:08
• Why not just replace IDs with unique random numbers? – Maeher Jul 10 '19 at 8:16
• Since we adhere to Kerckhoffs principle here, you'd need a keyed hash function to make it non-guessable. Otherwise the attacker would simply perform the hash for the calculation himself. So you could e.g. use a HMAC and take the leftmost bits. But Maeher's solution makes more sense, just store a secret table somewhere. – Maarten Bodewes Jul 10 '19 at 8:23

A six digit integer gives you a possible one million possible IDs. Consider this python code that hashes every possible ID using a properly vetted, secure, cryptographic hash function:

import hashlib
import time

t0 = time.time()

for i in range(1000000):
hashlib.blake2b(bin(i).encode("utf-8"))

t1 = time.time()

print(t1-t0)


It runs in around 400ms on my laptop. An attacker could generate a look-up table in less than a second that would map these output hashes back to the original employee numbers that they derive from.

In order to combat this, you'd have to use some kind of "hard" cryptographic hash like Argon2 or PBKDF2 in order to ramp up the computational complexity of generating a rainbow table.

But really this is just pushing the problem down the road and making it more difficult for yourself as well.

The better solution is to generate your own random lookup table and use that as a substitution in your spreadsheet. Consider:

import secrets

lookup = {}

for i in range(1000000):
lookup[i] = secrets.randbelow(1000000)

# employee id "662893" is mapped to which masked value?
print(lookup[662893])


The code is not quite what you want as there's no padding to six digits and the reverse lookup is likely the more useful one, and it does not check for collisions, but it serves to make the point.

Tackling collisions can be done by selecting IDs from the set of unused IDs, or just increasing the length of the random values so that the probability of collisions becomes negligible.

In this scheme where each employee is mapped to a unique ID, an attacker has no way of computing the original employee ID from the masked value without the lookup table, as they were generated randomly.

If the small (2x) memory overhead of this solution is unacceptable, Maarten's solution of using a keyed hash function is also viable. Simply use a HMAC construction with a secure hash function and a 32 byte key, and the attacker would have no way of bruteforcing the inputs without knowing the key.