5

Possible Duplicate:
How to generate 8 bytes unique id from GUID?

I need a unique key to identify a user at universal and key's length is just 8 byte, How can I do this in c# ?

Community
  • 1
  • 1
Linney
  • 63
  • 1
  • 1
  • 4
  • 1
    You won't have a lot of possibilities with only 8 bytes. The risk of collision is high. – Pierre-Alain Vigeant Jul 19 '11 at 15:38
  • @Linney - Read This: http://stackoverflow.com/questions/5678177/unique-id-from-guid – Security Hound Jul 19 '11 at 15:40
  • 6
    @Pierre-Alain: Not a lot of possibilities? Have you written any apps with more than 2^64 users? ;) – Jon Skeet Jul 19 '11 at 15:41
  • Blame the localization. In french, we use octet. Yeah I had in mind 2^8. Scratch that previous comment. – Pierre-Alain Vigeant Jul 19 '11 at 15:44
  • The limit is 8 byte because the key is saved to ram memory (this is requirement), if I used GUID value, it takes 16 bytes, then it will fill out the memory if system is up to 1 million users (16 x 1000.000), do you have any suggestion ? – Linney Jul 19 '11 at 15:47
  • @Linney: Whoa, nellie. 16 bytes gives you 128 bits gives you 2^128 = (2^10)^(12.8) ~ (10^3)^(12.8) ~ 10^38 combos. – jason Jul 19 '11 at 15:49
  • @Linney - Are you really worried about a million users loading their key all at the same time. You certainly are not going to keep every single user's key in memory all the time are you? – Security Hound Jul 19 '11 at 15:52
  • @ Ramhound If user login already, their key will be store in memory until end of user session, that why the length of key will overload memory and I need to limit its length, Ramhound, do u have any idea ? – Linney Jul 19 '11 at 15:59
  • @Linney - I wouldn't worry about the possability that a million people will be logged at once. As somebody already pointed out 8 bytes is not enough space to generate something that is unlikely not to be unique. Besides I already sent you to another thread as my suggestion. – Security Hound Jul 19 '11 at 16:04
  • @Ramhound- the system servers up to 255^8 people with 8 bytes unique key, so I'm not worry about the out of space of key, my problem is the key must be unique to identify user in system, but I don't have solution to generate them yet – Linney Jul 19 '11 at 16:07
  • @Linney: If a million people are logged in at once, and you're handling all their requests on a single machine, you're going to have *much* bigger issues than keeping track of all their GUIDs. Trust us. Just use a GUID, and once you get a few thousand people logging in simultaneously, you should be able to afford to throw a little more hardware at it. – StriplingWarrior Jul 19 '11 at 16:15
  • @Stripling: this is valuable consideration, I might have to separate service to dedicate server, it will solve the problem if using GUID and the request up to 10.000 (160M memory), thanks for advise, Stripling – Linney Jul 19 '11 at 16:22

7 Answers7

9

the following code will generate cryptographically unique 8 character strings:

 using System; 
using System.Security.Cryptography;
using System.Text;

namespace JustForFun
{


    public class UniqueId
    {   
        public static string GetUniqueKey()
        {
            int maxSize = 8;
            char[] chars = new char[62];
            string a;
            a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            chars = a.ToCharArray();
            int size = maxSize;
            byte[] data = new byte[1];
            RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
            crypto.GetNonZeroBytes(data);
            size = maxSize;
            data = new byte[size];
            crypto.GetNonZeroBytes(data);
            StringBuilder result = new StringBuilder(size);
            foreach (byte b in data)
            { result.Append(chars[b % (chars.Length - 1)]); }
            return result.ToString();
        }   
    }
}
Peter Bromberg
  • 1,498
  • 8
  • 11
  • Wow, is that overkill, or what? – jason Jul 19 '11 at 18:14
  • 4
    If you want cryptographically unique keys, no it's not overkill at all. Your choice. – Peter Bromberg Jul 20 '11 at 23:02
  • 2
    Don't think you need the `chars.Length - 1`. The maximum value of N mod X is always X - 1. – John Gibb Aug 08 '13 at 17:50
  • 1
    I know this question is old, but would you mind explaining how the strings become unique using this? To what extent are they unique? If I would use this function in a loop a several different points in time, would they continue to be unique? – JuhaKangas Jun 02 '14 at 13:52
  • 1
    @PeterBromberg by changing maxSize to 6, will be unique too ? – Mohammad Olfatmiri Nov 10 '15 at 17:15
  • You cannot say its unique, loop through a few million times and you already have collisions. It has high possibility to be unique but there is no guarantee like Guid.NewGuid() is quaranteed, but its 128bit. – RassK Jul 07 '17 at 14:16
  • What's the point of setting `size` to 8 twice or writing a single byte only to immediately overwrite it with 8 bytes? – Sinaesthetic Oct 02 '20 at 17:48
3

8 bytes is a size of a long integer in .net. You may start with a key of zero, increasing it by one for each user as they come. That would generate unique keys for more users than there are people on the Earth. If this does not solve your problem, please tell us more about your constraints.

LiborV
  • 164
  • 4
  • "You may start with a key of zero, increasing it by one": do you mean increase byte values by changing bit(0->255) for each bytes ? – Linney Jul 19 '11 at 16:03
  • @Linney, what he's describing is standard practice for identifiers on a specific database table. The first user gets ID 1, the second user is 2, the third is 3, and so on. However, this depends on there being a single place where these IDs are generated, because if two different systems assign ID 3 to different users, and then they try to share users, those two users will have the same ID. – StriplingWarrior Jul 19 '11 at 16:11
  • Stripling- yes, it's true, and it's not good in this way, humz – Linney Jul 19 '11 at 16:15
2

Generate a random long, and then convert it to a hex string.

Alternatively, just sequentially allocate from unsigned long.

jason
  • 236,483
  • 35
  • 423
  • 525
0

You could take a Guid.NewGuid().ToByteArray() and run it through some hashing algorithm with a resulting size of 8 Byte (= 64 Bit).

EDIT: There is a Google-developed Hash-Algo returning 64Bits (see http://code.google.com/p/cityhash/ ) which can be used on Guid.NewGuid().ToString() .

Yahia
  • 69,653
  • 9
  • 115
  • 144
0

With an 8 byte value (64 bits) you will have 2^64 possible outcomes. That's quite a few but significantly less than a GUID which has 2 ^ 128 possible values.

You could do something this simple:

        // generate 8 byte random value
        Random rnd = new Random();
        byte[] bytes = new byte[8];
        rnd.NextBytes(bytes);

        // displaying the value
        string myRndID = BitConverter.ToString(bytes).Replace("-", "");
        Console.WriteLine(myRndID);

For example:

XXXX           YY        ZZ
----           --        --
Random Value   Node ID   Days since epoch (of your definition)

Then:

Cat XXXX, YY and ZZ bytes together to create your pseudo-guID.

But that approach uses only random number generation. You could take a hint from the GUID algorithms (current and past) and populate some of the 8 bytes with a node ID value or a DateTime hash or something such combined with a random value to reduce the risk of collisions.

Still, the potential for collisions is there and if you do end up using an 8 byte pseudo-guID you should have a process defined for handling a collision.

Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
0

The point of a GUID is to be "Globally" Unique, meaning that the likelihood of anybody ever coming up with the same unique identifier that someone else is already using for a different object must be so small that you're willing to bet your business on it. Smarter minds than mine have determined that 16 bytes, combined with the right algorithm, is sufficient to achieve this. Since 8 bytes gives you only a tiny, tiny fraction of the number of possibilities that 16 bytes would give, I wouldn't recommend using 8-byte GUIDs.

However, if you really want to, you could do something like this:

public struct SmallGuid
{
    byte FirstByte;
    byte SecondByte;
    ...
}

Then you could either generate random values for these bytes, or leverage the real Guid class, and pull half the bytes off of it to populate your SmallGuid.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
0

See GUIDs are globally unique, but substrings of GUIDs aren't.

Hashing a GUID may work (but I'm not sure), but a better idea would be to come up with your own algorithm inspired by the GUID algorithm and based on the constraints of your system that you are aware of, for example:

  • If you know that you will only be generating IDs on a handful of systems then the MAC address portion of the GUID can be shortened.
  • Similarly if you assume that your app will be long gone in 100 years you can shorten the timstamp portion
  • If you only have one algorithm then there is no need for the algorithm identifier
  • If you also know that you wont be generating them too quickly you can shorten the "emergency uniquifier bits"
Justin
  • 84,773
  • 49
  • 224
  • 367