Dabiel Kabuto
Dabiel Kabuto

Reputation: 2862

How to obfuscate an integer?

From a list of integers in C#, I need to generate a list of unique values. I thought in MD5 or similar but they generates too many bytes.

Integer size is 2 bytes.

I want to get a one way correspondence, for example

0 -> ARY812Q3
1 -> S6321Q66
2 -> 13TZ79K2

So, proving the hash, the user cannot know the integer or to interfere a sequence behind a list of hashes.

For now, I tried to use MD5(my number) and then I used the first 8 characters. However I found the first collision at 51389. Which other alternatives I could use?

As I say, I only need one way. It is not necessary to be able to calculate the integer from the hash. The system uses a dictionary to find them.

UPDATE:

Replying some suggestions about using GetHashCode(). GetHashCode returns the same integer. My purpose is to hide to the end user the integer. In this case, the integer is the primary key of a database. I do not want to give this information to users because they could deduce the number of records in the database or the increment of records by week.

Hashes are not unique, so maybe I need to use encryption like TripleDes or so, but I wanted to use something fast and simple. Also, TripleDes returns too many bytes too.

UPDATE 2: I was talking about hashes and it is an error. In reality, I am trying to obfuscate it, and I tried it using hash algorithm, that it is not a good idea because they are not unique.

Upvotes: 2

Views: 4605

Answers (4)

kent-id
kent-id

Reputation: 737

Update May 2017

Feel free to use (or modify) the library I developed, installable via Nuget with:

Install-Package Kent.Cryptography.Obfuscation

This converts a non-negative id such as 127 to 8-character string, e.g. xVrAndNb, and back (with some available options to randomize the sequence each time it's generated).

Example Usage

var obfuscator = new Obfuscator();
string maskedID = obfuscator.Obfuscate(15);

Full documentation at: Github.


Old Answer

I came across this problem way back and I couldn't find what I want in StackOverflow. So I made this obfuscation class and just shared it on github.

Obfuscation.cs - Github

You can use it by:

Obfuscation obfuscation = new Obfuscation();
string maskedValue = obfuscation.Obfuscate(5);
int? value = obfuscation.DeObfuscate(maskedValue);

Perhaps it can be of help to future visitor :)

Upvotes: 6

CodesInChaos
CodesInChaos

Reputation: 108790

Encrypt it with Skip32, which produces a 32 bit output. I found this C# implementation but can't vouch for its correctness. Skip32 is a relatively uncommon crypto choice and probably hasn't been analyzed much. Still it should be sufficient for your obfuscation purposes.

The strong choice would be format preserving encryption using AES in FFX mode. But that's pretty complicated and probably overkill for your application.

When encoded with Base32 (case insensitive, alphanumeric) a 32 bit value corresponds to 7 characters. When encoded in hex, it corresponds to 8 characters.


There is also the non cryptographic alternative of generating a random value, storing it in the database and handling collisions.

Upvotes: 2

Jcl
Jcl

Reputation: 28272

For what you want, I'd recommend using GUIDs (or other kind of unique identifier where the probability of collision is either minimal or none) and storing them in the database row, then just never show the ID to the user.

IMHO, it's kind of bad practice to ever show the primary key in the database to the user (much less to let users do any kind of operations on them).

If they need to have raw access to the database for some reason, then just don't use ints as primary keys, and make them guids (but then your requirement loses importance since they can just access the number of records)

Edit

Based on your requirements, if you don't care the algorithm is potentially computationally expensive, then you can just generate a random 8 byte string every time a new row is added, and keep generating random strings until you find one that is not already in the database.

This is far from optimal, and -can- be computationally expensive, but taking you use a 16-bit id and the maximum number of rows is 65536, I'd not care too much about it (the possibility of an 8 byte random string to be in a 65536 possibility list is minimal, so you'll probably be good at first or as much as second try, if your pseudo-random generator is good).

Upvotes: 0

CheloXL
CheloXL

Reputation: 187

Xor the integer. Maybe with a random key that it is generated per user (stored in session). While it's not strictly a hash (as it is reversible), the advantages are that you don't need to store it anywhere, and the size will be the same.

Upvotes: 0

Related Questions