After certain privacy concerns Facebook rolled out a bunch of changes to their APIs, one being "scoping" user identifiers per app. In effect, this means that Alice's canonical facebook user ID is never shared through facebook APIs, but each app sees a unique never-changing value.
To formalize this through two functions:
mask(user_id, app_id)
unmask(masked_id, app_id)
These functions should satisfy some properties:
reversible:
user_id == unmask(mask(user_id, app_id), app_id)
secret: given
y = mask(user_id, app_id)
it should be 'hard' to obtain the originaluser_id
.deterministic:
mask(user_id, app_id) == mask(user_id, app_id)
, whereuser_id == user_id
andapp_id == app_id
collision resistant: for all user ids, given the same app_id, it should not be the case that
mask(user_id1, app_id) == mask(user_id2, app_id)
After a lot of reading, I have come up with two possible implementations:
- Stateful: store a triple
(user_id, app_id, hash(user_id, app_id))
. - Stateless: for each
app_id
generate & store asecret
, andencrypt(user_id, secret)
on the fly. the encryption should be a deterministic cypher, such as AES-SIV.
From the get go, I'd like to avoid a stateful implementation. I am not sure however as to the validity of the stateless approach as I'm not very familiar with deterministic symmetric cyphers, and their security implications.
Is there some other approach I might be missing here? I think this is a deceptively easy problem, looking forward to get some insight.