I\'m looking for an easy and reversible method of obfuscating integer IDs. Ideally, I\'d want the resulting obfuscation to be at most eight characters in length and non-seq
I realize this is an old post, but I thought it might be helpful to post my technique for obfuscating integer ids
Cons: does use more than 8 characters, only good for id values under 33 million
Pros: does not require a key to de-obfuscate, URL/cookie friendly, generates a different value every time which makes it harder to break, no collisions, includes a checksum feature to eliminate random / brute force attempts to break (one issue that the above post do not address, is people trying to "scrape" your site. If I see a url ending in id=123 I know I can try id=124 etc... to get additional data, this is why some of the XOR examples are likely not a good idea)
I would recommend tweaking this a bit (which I've done for mine) as I don't think you should ever use a publically published obfuscation technique, but it is a good place to start.
Happy coding!
public static string ObfuscateId(int id)
{
try
{
string rtn;
int sid = id + 279;
int xm = sid * 3;
int xl = xm.ToString().Length + 10;
string sc = xl.ToString().Substring(1, 1);
string fc = xl.ToString().Substring(0, 1);
string csum = sid.ToString().Substring(sid.ToString().Length - 3);
rtn = Guid.NewGuid().ToString().Replace("-", "").ToLower();
rtn = sc + rtn.Substring(2, 26) + fc;
rtn = rtn.Remove(4, 3).Insert(4, csum);
rtn = rtn.Remove(xl, (xl - 10)).Insert(xl, xm.ToString());
rtn = rtn.Replace('1', 'g');
rtn = rtn.Replace('2', 'h');
rtn = rtn.Replace('3', 'i');
rtn = rtn.Replace('4', 'w');
rtn = rtn.Replace('5', 'y');
rtn = rtn.Replace('6', 'u');
rtn = rtn.Replace('7', 'z');
rtn = rtn.Replace('8', 'l');
rtn = rtn.Replace('9', 'v');
rtn = rtn.Replace('0', 'n');
rtn = rtn.Replace('c', 'j');
rtn = rtn.Replace('d', 'p');
rtn = rtn.Replace('f', 'q');
return rtn.ToUpper();
}
catch
{
return "ERROR BAD ID";
}
}
public static int DeObfuscateId(string obtxt)
{
try
{
string rtn;
int id;
rtn = obtxt.ToLower();
rtn = rtn.Replace('g', '1');
rtn = rtn.Replace('h', '2');
rtn = rtn.Replace('i', '3');
rtn = rtn.Replace('w', '4');
rtn = rtn.Replace('y', '5');
rtn = rtn.Replace('u', '6');
rtn = rtn.Replace('z', '7');
rtn = rtn.Replace('l', '8');
rtn = rtn.Replace('v', '9');
rtn = rtn.Replace('n', '0');
rtn = rtn.Replace('j', 'c');
rtn = rtn.Replace('p', 'd');
rtn = rtn.Replace('q', 'f');
string sc = rtn.Substring(0, 1);
string fc = rtn.Substring(rtn.Length - 1);
int xl = int.Parse(fc + sc);
int mv = int.Parse(rtn.Substring(xl, (xl - 10)));
int sid = mv / 3;
id = sid - 279;
string csum = sid.ToString().Substring(sid.ToString().Length - 3);
string xsum = rtn.Substring(4, 3);
if (csum!=xsum)
{
return -99999;
}
return id;
}
catch
{
return -99999;
}
}
}
Just get a MD5/SHA1 hash of the integer's byte representation. You are guaranteed not to get collisions.
I realise this was asked 7 months ago so you will have found a solution by now, but solution I've come across is a combination of Skip32/Skipjack cipher + a base32 encoding. The perl example (since that's where I know of one) shows:
use Crypt::Skip32::Base32Crockford;
my $key = pack( 'H20', "112233445566778899AA" ); # Always 10 bytes!
my $cipher = Crypt::Skip32::Base32Crockford->new($key);
my $b32 = $cipher->encrypt_number_b32_crockford(3493209676); # 1PT4W80
my $number = $cipher->decrypt_number_b32_crockford('1PT4W80'); # 3493209676
I don't know of a c# implementation, but a perl one is http://search.cpan.org/perldoc?Crypt::Skip32::Base32Crockford and the two constituent parts for a ruby one are https://github.com/levinalex/base32 and https://github.com/patdeegan/integer-obfuscator. Between the two of them you should be able to port it to any language you need.
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.
Just adding variety to an old answer. Perhaps someone will need it. This is an obfuscation class I made sometime back.
Obfuscation.cs - Github
You can use it by:
Obfuscation obfuscation = new Obfuscation();
string maskedValue = obfuscation.Obfuscate(5);
int? value = obfuscation.DeObfuscate(maskedValue);
Cheers, hopefully it can be of use.
In case other people are interested, somebody adapted a 32-bit block cipher a few years back that's especially useful for this task.
There is also Perl and Ruby port of the above available:
If you need the result in 8 characters or less, you can use a hex or base64 representation.
Nice project for handling that with libraries in most languages: http://hashids.org/