1

I need multiple "random" URLs that just mask the original URL, i.e.:

/ABC
/CBA
/CAB

All resolve to /6

I came up with matching a letter to a number and then you can sum them to the single value.

A = 1
B = 2
C = 3
...

/ABC = A + B + C = 6
/CBA = C + B + A = 6
/CAB = C + A + B = 6
...

Is there a name for this? It doesn't seem to be reversible hashing.

Is there an existing algorithm to generate+resolve them?

7
  • 1
    The correct name is hash collision. Hash collision is a bad thing for hash functions; therefore, well-designed hash functions will minimize hash collision. Based on your usage, you probably aren't looking for a "hash function" per se, but instead try to look for an information concealment function, preferably one that doesn't require maintaining a database of keys and values.
    – rwong
    Commented Mar 23, 2016 at 6:42
  • 1
    You might also need to think about whether security is a concern, i.e. would it matter if your scheme is trivially breakable by an outsider.
    – rwong
    Commented Mar 23, 2016 at 6:44
  • 2
    Hashing always involves collisions. If it didn't, it would be encryption. The trick about hashing is to design your hash function so that accidental collisions are unlikely. Commented Mar 23, 2016 at 7:08
  • 3
    It's called encryption. You get different ciphertext if you use different nonces/IVs. Commented Mar 23, 2016 at 9:39
  • 1
    That's not a hash, it's obfuscation.
    – Pieter B
    Commented Mar 23, 2016 at 14:02

3 Answers 3

3

As pointed out by the other commentors you are not really looking for a hash function, but instead just need a simple encryption. As you state that trivial security breaches are of no consequence, you can rely on very simply substitution ciphers. It will look like gibberish, but still work out nicely.

The name that comes closest to such a thing is the generation of cipher texts in encryption. "Cipher" simply means that unreadable gibberish that you get after you encrypted your precious text with a secret key. In your case, since you only want that cipher you can just include the key, trivially breaking the encryption, and for your interpretation end you just extract the key and de-crypt the remaining part, which would be the cipher.

Note that this approach when combined with an alphanumeric encoding like BASE64 can be applied with pretty much any encryption algorithm you fancy. Roll your own (viable, since you don't need it to actually be safe), or take a really strong standard implementation of something like AES. Doesn't really matter.

Here's an example: Let's say you just want to use the characters A-Z and you perform a rotation cipher (like ROT-13), such that the first character is the "key". You can take any simple URL-word like "DATA" and rotate it based on an additional first character. Let's interpret A as 0, then B is a rotation of 1, so D would become the letter E (one after D), A becomes B, and so on. The character Z becomes A again via a simple modulo operation.

This immediately gives you 25 different variations of "DATA" which look "personalized" yet "unintelligible". Something like this:

AEBUB BFCVC ...

1

If you're using hashing, you might need a dictionary to resolve a hashed URL to a normal URL; e.g.

Dictionary<int, Uri> urlHashes;

So that you can do:

Uri originalURL = urlHashes[hashKey];

Otherwise you will have to check the received hash against every URL that exists in your scope; e.g.:

List<Uri> allUrls;
foreach (Uri u in allUrls)
{
     int hash = u.GetHashCode();
     if (hash == hashKey)
     {
         return u;
     }
}
throw new InvallidUrl()

There are two options to create multiple keys pointing to te same URL:

  1. Add a random number or string to the URL and calculate the hash over the combination; e.g.:

    const int mySecretRandomPrime = 3943;
    int randomNumber = new Random().Next(1000);
    int urlHash = (url.GetHashCode() * mySecretRandomPrime) + randomNumber;
    
    return urlHash;
    

    If you store the keys–URL pairs you can lookup the original URL via the composite hash that you have stored.

    Or, if you do not store all provided url hashes, you can require the client to sent both the combined urlHash and randomBumber to you and you can iterate over the list of known URLs, calculate the combined hash and return the matching URL; e.g.:

    List<Uri> allUrls;
    const int mySecretRandomPrime = 3943;
    
    foreach (Uri u in allUrls)
    {
        int hash = (url.GetHashCode() * mySecretRandomPrime) + randomNumber;
        if (hash == hashKey)
        {
            return u;
        }
    }
    throw new InvallidUrl()
    
  2. If you opt to store key–url-pairs, you can also leave out the URL hashes completely and just return (cryptologically) random GUIDs/UUIDs.

0

I came up with this, it only works on numbers (a string-to-number conversion could happen outside if necessary).

It converts the number to binary and then maps lowercase letters that are either odd (a, c, e, ...) or even (b, d, f, ...) to each 0 or 1 respectively. So

74 =   1001010 =   "baababa"
74 =   1001010 =   "pcgtghy"
74 =  01001010 =  "etcetera"

This is the code in Javascript

const a = 'a'.charCodeAt(0);
const length = 'z'.charCodeAt(0) - a;

function padLeft (string, len){
    while(string.length < len) { string = 0 + string; }
    return string;
}
function decode (val) {
    return (val.charCodeAt(0) - a) % 2;
}
function encode (odd) {
    // generate a random letter in the available range
    // but make sure it's odd or even
    return String.fromCharCode(a + Math.floor(length * Math.random() / 2) * 2 + parseInt(odd, 10));
}
function generate (number, minLength = 0) {
    return padLeft(number.toString(2), minLength).split('').map(encode).join('');
}
function solve (code) {
    return parseInt(code.split('').map(decode).join(''), 2);
}

And this is the usage, it also accepts a minimum length parameter

code = generate(74);     console.log(code, solve(code));
code = generate(74, 5);  console.log(code, solve(code));
code = generate(74, 10); console.log(code, solve(code));
code = generate(74, 20); console.log(code, solve(code));

Also on npm

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.