
AES-based Synthetic IDs: deterministic AE for 64-bit integers - beefhash
https://github.com/iqlusioninc/aes-sid
======
femto113
Similar ideas go back quite a ways. Here’s notes from a Perl library based the
Skipjack cipher, this wound up inspiring some of my own work and I wound up
porting it to node.js.

> One example where Crypt::Skip32 has been useful: You have numeric database
> record ids which increment sequentially. You would like to use them in URLs,
> but you don't want to make it obvious how many X's you have in the database
> by putting the ids directly in the URLs.

> You can use Crypt::Skip32 to scramble ids and put the resulting 32-bit value
> in URLs (perhaps as 8 hex digits or some other shorter encoding). When a
> user requests a URL, you can unscramble the id to retrieve the object from
> the database.

[https://metacpan.org/pod/release/ESH/Crypt-
Skip32-0.17/lib/C...](https://metacpan.org/pod/release/ESH/Crypt-
Skip32-0.17/lib/Crypt/Skip32.pm)

------
sjnu
I’m curious what properties this has that aes(0||id) doesn’t.

~~~
jemfinch
It's reversible. That's the whole point. You don't need to keep a separate
table or column for the hashed id.

~~~
rainsford
Isn't AES encryption also reversible? The use-case for AES-SID appears to be
mapping 64-bit ID values to 128-bit ciphertexts and reversibly producing an
authenticated 64-bit ID value from the 128-bit ciphertext. Zero padded AES
does both of these things as far as I can tell.

------
benmmurphy
i see tptacek is stalking this thread so i'm going to post a semi-off topic
question.

with AES-GCM is it safe to generate nonces randomly? i see some
recommendations that after a certain number of encryption operations you
should rotate keys.

i haven't really looked at AES GCM SIV but looking at the description of the
algorithm on this github page it doesn't look like it fixes 'misuse' if your
misuse is generating random nonces and generating huge numbers of ciphertexts.

i see AWS has a KMS solution that encrypts stuff server side using AES-GCM
that don't mention anything about IV generation and only support rotating keys
once a year. is it safe to assume this scheme is safe if you are encrypting
lots of ciphertexts with a single key?

~~~
api
Search for the birthday paradox. Basically if you assume an attacker that can
store every messages, as used nonces accumulate the chance of a collision
increases. It does not remain constant, as naive intuition would suggest.

The maximum suggested number of uses per key can be calculated based on the
desired security bound (chance of a collision with past messages) and the size
of the nonce/IV.

If you want a rule of thumb, (N/2)-1 the number of bits in the nonce is not
too bad. So if you have 64-bit nonces, you should send no more than 2^31
messages.

This only applies to random nonces. If you are incrementing the nonce
sequentially, you get as many nonces as the range of your integer. But here be
dragons: if you lose track, you will _definitely_ repeat nonces! This is why
schemes that save and restore the nonce value are dangerous. If you lose power
and restore an old value, all the nonces from then until the latest real
position will repeat.

Usually it's safe to use simple incrementing nonces with ephemeral keys that
live only as long as a session and a specific instance of the app/OS/whatever.
You can restart the nonce with a new key no problem. Just be sure your
increment is protected by a mutex or something like std::atomic<> if there are
multiple threads or two threads could send the same nonce.

~~~
benmmurphy
yer. i've always used N/2 as a rule of thumb and checked if that is a big
enough number. i saw this quote from NIST on crypto exchange in regards to
AES-GCM. i would usually assume 96 bit -> 48 bit would be enough but they have
what I think is some pessimistic advice:

[https://crypto.stackexchange.com/questions/42982/safety-
of-r...](https://crypto.stackexchange.com/questions/42982/safety-of-random-
nonce-with-aes-gcm)

>> AES-GCM takes a 96-bit nonce and NIST says that you can only encrypt 2^32
messages under a single key if using random nonces. This is because if you
throw 2^32 balls at 2^96 buckets then you have roughly a 2^-33 chance of
getting two in the same bucket and NIST drew the line there. That probability
might seem either high or low to you. It's pretty small in absolute terms and,
unlike a work factor, an attacker can't spend resources against it, but it's a
very long way from the safety margins that we usually use in cryptography.

i notice libsodium uses xchacha20 which has a larger nonce which is 192 bits
size. and in there docs they say:

>> Unlike plain ChaCha20, the nonce is 192 bits long, so that generating a
random nonce for every message is safe.

Not sure if they are referring to both libsodium ChaCha20 implementations. One
of them is obviously very unsafe with only 64 bit nonce, but one is 96 bit the
same as AES-GCM.

~~~
blattimwind
> i would usually assume 96 bit -> 48 bit would be enough but they have what I
> think is some pessimistic advice:

The "You have n Bits, then you need 2^n/2 tries for a birthday attack, so your
real 'security level' is n/2 bits" rule captures the expected value of tries
to get a collision. That's the 50 % point. You don't want to design your
crypto system in a way that results in a 50 % chance of at least one nonce
repetition.

------
bob1029
This is an interesting approach for primary key obfuscation.

I recently stumbled upon something that I feel might be even more powerful -
Hashing complex types into 256-bit keys. E.g. If you had some type
representing the composite keys of a Customer in your system (email address,
phone number, etc.), you could serialize this instance, run it through SHA256,
and as long as the same process is used for lookups, you can get everything
back out as expected.

Essentially, you can compress your entire scope of composite key data into a
single 256 bit value. Just like with GUID keys, this can be pre-computed on
each client (whereas autoincrement cannot). This approach is very clever IMO
because it can be used directly on top of any universal byte[]/byte[] key-
value store. Your keys are all 256 bit values corresponding to the SHA256 of a
serialized complex key instance. The type information can be encoded into the
key itself (e.g. hash the fully-qualified type name as well).

~~~
bascule
If you use an unkeyed hash (as opposed to a PRF) on low-entropy inputs, they
can be preimaged by an attacker.

This is especially problematic in the case of PII like email address/phone
number

