8

I am developing a webapp that does not reveal record count, because it hides the primary key. I am looking for a better way to do this.

My favorite idea is to encrypt the ID itself with a block cipher, because that would require not additional tracking tables, and if the block size is equal to the key size, it should work fine.

However, I don't want a 128 bit block size, because it would take awhile to type example.com/records/MTZjaHJzRm9yMTI4Yml0cw (Base 64 representation)

The ideal block size would be fully adjustable. I want to be able to make an 8 digit ID input that results in an 8 digit output, that is collision free by using a permanently stored random key. The input would be the real primary key, and the output would be the identifier shown to the public. I may decide to change the digit length, or to switch to Base64 identifiers, and I would like for the algorithm to be flexible enough to accomodate this?

Can you recommend an encryption routine for such short data and outputs? I don't care whether the key is short or not, only the data and output has to be.

8
  • 3
    Why not just create a set of randomly generated IDs of whatever size you want, and creating an additional table to map between the random public ID and the sequential real ID? You could actually guarantee there's no collisions that way, which you wouldn't necessarily be able to do if you're just encrypting the sequential IDs (even if unlikely to occur).
    – Kitsune
    Apr 4, 2013 at 21:27
  • What database are we talking about? But basically, I was also wondering the same thing that @Kitsune is asking in the comment. Also, something along the lines of rnd(90000000)+10000000 to have random values of 8 characters in length and then either checking for their existence and repeating generation if needed, or having a unique index on that field, trying to append data and if it fails on index value not being unique - recalculating another value. You could create (or Google for) a stored procedure in most RDBMS to do this for you.
    – TildalWave
    Apr 4, 2013 at 21:36
  • @Kitsune, I could indeed use a separate table or field. I was just noticing how there are block ciphers that do this collision free on a fixed key length (128 bits), and was wondering if I could find one that allows me to specify my own key length (32 bits, 24 bits), or use BigInteger (so I could say digit count instead of bit count). If there is no such cipher then I'll the separated table or field idea. Apr 4, 2013 at 21:49
  • @TildalWave, MySQL, but I was thinking it would not matter. And yes, I could keep a database of the public identifiers, but would prefer to have them cryptographically generated so I don't need to make a new field, and I wouldn't need to store all of those and do duplication checking of random data. Apr 4, 2013 at 21:51
  • 1
    @TildalWave - I think a hash doesn't solve the problem. It would be convenient to have a function that encrypts the (auto-incremented) primary key of a database row, so you can find the row again. The encryption doesn't need to be strong, it should just obfuscate the primary key. And with a generated random key, you would need to check if such a key already exists. Apr 5, 2013 at 11:32

1 Answer 1

4

What you want is format-preserving encryption. There is unfortunately no ready-to-use standard for that, but some reasonable constructions are known. I would recommend the Thorp shuffle which is an extremely unbalanced Feistel scheme; given enough rounds, this can implement a permutation which is close to the optimal (except that a Feistel scheme is necessarily an even permutation).

Be aware that implementing your own cryptographic algorithm is fraught with perils. If you are not comfortable with the article quoted above, find someone else who is. (Fortunately, in your specific scenario, if you use a weak cipher the penalty is limited: attackers may guess the number of records or predict the next primary key value.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .