1

I wish to obfuscate a 5 digit number

Properties of the obfuscated number that I care about:

  • it's impossible (or as a fall back, extremely unlikely) to collide with other obfuscated numbers
  • it's also a 5 digit number (no alpha characters please)
  • it's not easily determinable by a regular human without computational assistance (e.g. it's not something obvious like "multiply by 2 and subtract 5"
  • it's an algorithm ... as opposed to storing a look up table of all possible 5 digit numbers to their corresponding hash or some other "brute force" technique

Properties of the obfuscated number that I don't care about:

  • whether it's repeatable or not i.e. if "12345" always results in "73624", I okay
  • whether it's cryptographically secure or not

Thus far I haven't found anything that fits my requirements... but am hoping this is due to poor memory, incomplete education or dubious lifestyle choices rather than no "nice" solution being present.

An example that can be easily translated into C# would be a bonus.

Update:

I'm investigating using the idea of doing a simple bit mapping for the moment.

   static List<int> bitMapping = new List<int>() { 8, 6, 9, 3, 7, 5, ... etc... };

    private static int Obfuscate(int number)
    {
        var bits = new bool[bitMapping.Count];
        foreach (var ordinal in bitMapping)
        {
            var mask = (int)Math.Pow(2, ordinal);
            var bit = (mask & number) == mask;
            var mappedOrdinal = bitMapping[ordinal];
            bits[mappedOrdinal] = bit;
        }

        var obfuscatedNumber = 0;
        for (var ordinal = 0; ordinal < bits.Length; ordinal++)
        {
            if (bits[ordinal])
            {
                obfuscatedNumber += (int)Math.Pow(2, ordinal);
            }
        }
        return obfuscatedNumber;

It seems to meet most of my requirements thus far.

lzcd
  • 1,325
  • 6
  • 12
  • 4
    By definition, a hash is repeatable. If you don't care about that property, why don't you just replace the number with a pseudo-randomly generated number? – paddy Jan 30 '13 at 00:12
  • 1
    If you don't care of consistency "I don't care about: whether it's repeatable" then return random value – zerkms Jan 30 '13 at 00:12
  • Where will it be stored? I ask because multiplying by two and subtracting 5 is not easily decrypted by a user just looking at the numerical value.. it could be anything originally.. – Simon Whitehead Jan 30 '13 at 00:12
  • @paddy Happy with psuedo random... just need the psuedo random numbers not to collide – lzcd Jan 30 '13 at 00:13
  • @lzcd: create an array of 100k integers and pick numbers from it. After you picked - remove it from the array – zerkms Jan 30 '13 at 00:14
  • This is interesting, but I don't think it's a good fit for SO in that it's too subjective. There isn't a single "right" answer to this question. – templatetypedef Jan 30 '13 at 00:14
  • 2
    You want to ensure that two 5-digit random numbers won't be the same?! You can't, but it is unlikely. I think it's time that you explained WHAT this is for and HOW you intend to use it. – paddy Jan 30 '13 at 00:14
  • @templatetypedef If multiple solutions are provided which fit the cirteria stated then I'll happily concede the question is a bad fit... but thus far a single solution, let alone multiple ones, has yet to be provided. – lzcd Jan 30 '13 at 00:16
  • 1
    One way: Add an offset to each digit, with wrap-around so that they remain digits - one fixed offset per position, so, say, 3, 5, 7, 4, and 8. Kind of like a combination lock to a safe. To decrypt, subtract the values. – 500 - Internal Server Error Jan 30 '13 at 00:17
  • @500-InternalServerError I like the sound of that and would recommend offering it as an answer. – lzcd Jan 30 '13 at 00:19
  • @paddy No fussed if it's random or not. (Randomly generated numbers however do tend to present the need to store them so that one can avoid collisions... which is one aspect I'm hoping to avoid for numerous reasons). The main thing I'm interested in is avoiding an obvious correlation between the source and obfuscation number. – lzcd Jan 30 '13 at 00:26
  • @500-InternalServerError: Maybe I am missing something here, but isn't that the same as just adding 35748 to the number? – Gray Jan 30 '13 at 00:28
  • The identify function handles all of your requirements, with the advantage that if the user starts making operations to guess the actual number, they will never find it (since they already have the actual number). – mmgp Jan 30 '13 at 00:34
  • i guess by repeatable he means unique, ie there could be multiple representations that point back to the same input. With both representations the same size clearly the transformation must be unique so that's an irrelevant non-requirement. – agentp Jan 30 '13 at 01:09
  • I just noticed I wrote "identify function", I actually meant the dummy "identity function". @george is that comment towards my other comment ? I don't see how it makes sense, supposing you understood I meant "identity function", and not something else. – mmgp Jan 30 '13 at 01:13
  • @Gray: You're not missing anything. – 500 - Internal Server Error Jan 30 '13 at 01:27
  • @500-InternalServerError: Ha, Ok. I just never really thought about it like how you phrased it I guess. And the OP suggesting you post it as an answer when there was one like that convinced me that I must be missing something. – Gray Jan 30 '13 at 01:34
  • [Other question](http://stackoverflow.com/q/8554286/1009831) has similar (though a little bit stricter) requirements. – Evgeny Kluev Jan 30 '13 at 09:59

2 Answers2

2

That might be too simple for your needs, but something that works and might not be as obvious as an addition is the XOR operation :

12345 ^ 65535 = 53190
53190 ^ 65535 = 12345

As noted in comments it is important that the second operand is of the form (2n - 1) to avoid collisions (so that every bit in the original number is inverted). It also needs to be long enough that its number of bits is greater or equal than the first operand.

You might also have to pad-left with 0's to make the result a 5-digit number.

Xavier Poinas
  • 19,377
  • 14
  • 63
  • 95
  • Someone smarter than me might be able to say why, but I *suspect* there would be collisions with this because XOR is commutative. Maybe if you keep the key constant, then it wont be an issue? This is just speculation, as I haven't researched it enough to dispute your answer. – Gray Jan 30 '13 at 00:35
  • 1
    If you choose the second constant so that it is a power of 2 minus 1 (i.e., all 1's in binary), then there will be no collisions. – Xavier Poinas Jan 30 '13 at 00:36
  • Ah, thank you for the explanation. That makes sense. What if you do a series of XORs and additions? Would that make for a legitimate 1:1 substitution? – Gray Jan 30 '13 at 00:43
  • 2
    It would, because the composition of 2 [bijections](http://en.wikipedia.org/wiki/Bijective#Composition) is a bijection. – Xavier Poinas Jan 30 '13 at 00:47
  • I feel like that would make for a pretty difficult to de-obfuscate number then. Not that it would be impossible to crack, but it would surely have taken me some time to figure it out, ha! – Gray Jan 30 '13 at 00:54
  • I guess it wouldn't be too bad. You could throw in some bit rotations/permutations as well. Though people will argue that [security through obscurity](http://en.wikipedia.org/wiki/Security_through_obscurity) isn't a very good strategy. – Xavier Poinas Jan 30 '13 at 01:36
0

If you don't want collisions then multiplication/division are out. In which case then I would

  1. Add a 5 digit seed value to your number, if it overflows into six digits discard the sixth.

  2. Reorder the digits in some consistent way.

E.g.

12345 + 97531 = 109876 or 09876 after discard overflow Reorder to 68097

AlSki
  • 6,868
  • 1
  • 26
  • 39
  • 1
    How "If you don't want collisions" correlates with "Reorder the digits in some way."? – zerkms Jan 30 '13 at 00:19
  • It doesn't. The collisions would be inherent from any multiplication or division where you are ignoring overflow or underflow. i.e. 00000*5 =0, 2000*5 = 100000 which rounds to 00000, and 00020/5 = 00004, 00021/5 = 00004.2 which rounds to 00004. – AlSki Jan 30 '13 at 14:22