1

I want to create a method in c# that will accept my unique email or username and will return me a unique string just like youtube's video id (https://www.youtube.com/watch?v=_MSYfOYFF14). I can't simply use GUID because I want to generate a unique string against every user and it will remain same for that user each time I hit that method. So is that possible anyhow?

Ask
  • 3,076
  • 6
  • 30
  • 63
  • 3
    an hash function... but beware of upper and lowercase! – xanatos May 28 '18 at 10:13
  • @xanatos, are you talking about GetHashCode() method? I am trying to some other way because sometimes it returns int id in nagative – Ask May 28 '18 at 10:15
  • Don't count on `GetHashCode()` to be anything near unique. See this answer for the hash functions @xanatos is referring to: https://stackoverflow.com/questions/800685/which-cryptographic-hash-function-should-i-choose – C.Evenhuis May 28 '18 at 10:23
  • Is this string going to be exposed somewhere? I mean, does it need to be encoded to prevent someone to read username or password? – Tomas Chabada May 28 '18 at 10:25
  • 4
    xanatos means hash function like md5, sha-256 and so on. Run such function over your string (first convert string to bytes using appropriate encoding, like UTF8), convert resulting bytes to string (with `Convert.ToBase64String` for example) and you are done. – Evk May 28 '18 at 10:26
  • @tomassino no, that's not a requirement – Ask May 28 '18 at 10:27
  • @Evk yeah thanks. I have just understood that – Ask May 28 '18 at 10:28
  • I found this link very helpful: https://stackoverflow.com/questions/5216708/hash-function-net Thanks @xanatos – Ask May 28 '18 at 10:30
  • Ok, if it is not going to be exposed than why just not use something like: `var uniqueString = $"{uniqueName}|{uniqueEmail}";` – Tomas Chabada May 28 '18 at 10:32
  • 1
    @Ask You should first `.ToUpperInvariant()`, to remove differences between upper and lower case – xanatos May 28 '18 at 10:35
  • @xantos, I have already done that. But can you tell me one more thing? I am using MD5CryptoServiceProvider to achieve my requirement but when I convert byte array to base64string then sometimes I am getting a string with slash (/) like this: 7xblL1/58jTB/hQ8tXihig== I doubt that it might create a problem when I pass it in querystring. It might be treated as another param. So is there anyway I can restrict all the special characters – Ask May 28 '18 at 10:43

3 Answers3

2

1) Use the MD5 to get the byte array

2) Convert the byte array to string

3) Remove last two character

    using System.Security.Cryptography; 
    //...
    private string GenerateUniqueString(string input )
    {
        using (MD5 md5 = MD5.Create())
        {
            byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(input));
            var res = Convert.ToBase64String(hash);
            return res.Substring(0, res.Length - 2);    
        }
    }
L_J
  • 2,351
  • 10
  • 23
  • 28
  • Can you tell me one more thing? I am using MD5CryptoServiceProvider to achieve my requirement but when I convert byte array to base64string then sometimes I am getting a string with slash (/) like this: 7xblL1/58jTB/hQ8tXihig== I doubt that it might create a problem when I pass it in querystring. It might be treated as another param. So is there anyway I can restrict all the special character – Ask May 28 '18 at 10:51
  • You can simply replace slash (/) with some url friendly character ( underscore ( _ ) for example): res = res.Replace('/', '_'); – L_J May 28 '18 at 11:05
  • I've found a better way to solve my problem. I have used Base64UrlEncoder.Encode() method and it has removed all the special characters from the string – Ask May 28 '18 at 11:12
0

If it is not going to be exposed to someone else then it can be human readable. Stated that username or password is unique, that means that also combination of these values concatenated with some character (that can not be used in email and username) must be unique. The result is then very simple:

var uniqueString = $"{uniqueName}|{uniqueEmail}";
Tomas Chabada
  • 2,869
  • 1
  • 17
  • 18
0

Simple example of hashing together multiple strings.

public static string Hash(bool caseInsensitive, params string[] strs)
{
    using (var sha256 = SHA256.Create())
    {
        for (int i = 0; i < strs.Length; i++)
        {
            string str = caseInsensitive ? strs[i].ToUpperInvariant() : strs[i];
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            byte[] length = BitConverter.GetBytes(bytes.Length);
            sha256.TransformBlock(length, 0, length.Length, length, 0);
            sha256.TransformBlock(bytes, 0, bytes.Length, bytes, 0);
        }

        sha256.TransformFinalBlock(new byte[0], 0, 0);
        var hash = sha256.Hash;
        return Convert.ToBase64String(hash);
    }
}

There is a caseInsensitive parameter, because foo@bar.com is equivalent to foo@BAR.COM (and quite often FOO@bar.com is equivalent to all of them). Note how I'm encoding the strings: I'm prepending before each string the length of the encoded string (in UTF8). In this way "Hello", "World" is differento from "Hello World", because one will be converted to something similar to 5Hello5World while the other will be "11Hello World".

Usange:

string base64hash = Hash(true, "Donald Duck", "donaldduck@disney.com");

Note that thanks to the params keyword, the Hash method can accept any number of (string) parameters.

xanatos
  • 109,618
  • 12
  • 197
  • 280