+ Reply to Thread
Results 1 to 29 of 29

Thread: Getting a guaranteed unique ID

  1. #1
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default Getting a guaranteed unique ID

    Quick question:

    How might I go about getting a unique identifier for a system, such as the HDD ID?

    And what can I use that works on Win32, OSX, and Linux?

    Cas

  2. #2
    Senior Member
    Join Date
    Jul 2004
    Posts
    280

    Default

    There is nothing you can use that will be guaranteed to be unique across multiple platforms.

    The closest thing is the MAC address of the network adapter (if any) hooked up to the system, but there's no 100% guarantee it will be unique because even though they are all supposed to ship with a unique assigned address, most of them can be flashed with a new address if the user really wants to.

  3. #3

    Default

    GUIDs would do the trick. It's very hard to generate these in a portable way. Here's an article that could get you started :

    http://www.ics.uci.edu/~ejw/authorin...s-guids-01.txt


    Oh, it's remarkably easy to generate these in windows, just look up UuidCreate() , and on linux/unix there's something called Libuuid, but don't take my word for it.
    Dominique

  4. #4
    Moderator
    Join Date
    Jul 2004
    Location
    Zürich, Switzerland
    Posts
    1,966

    Default

    Do you need it to be tied to the hardware or just a random but unique ID? In that case I'd use a GUID... it's not guaranteed to be unique but it's highly unlikely that you generate two identical GUIDs. Even more so with the kind of sales figures indies have.
    Gabriel Gambetta
    Google Zürich - Formerly Mystery Studio

  5. #5
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    GUIDs aren't quite what I want, although I think there is a unique component in them... I want to be sure of getting the same number whenever I install an app on a particular machine, not a unique one every time.

    Cas

  6. #6
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    Tied to the hardware. This is not an indie-specific requirement; it's for the LWJGL which has applications beyond indie games.

    Cas

  7. #7
    Senior Member
    Join Date
    Jul 2004
    Location
    Baltimore, Maryland
    Posts
    331

    Default

    Try the network card MAC Address (http://www.webopedia.com/TERM/M/MAC_address.html) That is unique for each network card in existence. Manufacturers are allocated blocks of them from some agency (I forget who) and set each card to one.

    Using this will uniquely identify a computer. Of course this only works if the computer has a network card, but most do these days... either installed in a slot, or built into the motherboard. The number of computers that dont have a network card would be insignificant.

    Edited to add a better link to the definition...

    http://en.wikipedia.org/wiki/MAC_address
    Last edited by Bluecat; 08-12-2004 at 06:19 AM.

  8. #8
    Senior Member
    Join Date
    Aug 2004
    Location
    Utah, USA
    Posts
    844

    Default

    Are you planning on using this in some sort of copy protection technique?

    I had an idea a while back of using the MAC address of the card as part of the registration/unlock key. This would make it so that that key would only unlock the game on that machine. If someone else tried to use that same key on another machine, it wouldn’t work. It seemed like a nice idea, but there are some caveats, such as what happens if the game is purchased by a parent on the “parents PC”, and then that key is used on the “kids PC” (there are many homes with more than one computer now, that they are so cheap). Also what happens if they have to replace the network card (it goes bad), and then later reinstall the game, or what happens when they upgrade to a new computer. This would frustrate some users with some valid uses.

    I am against software piracy, but I think a lot of copy protection techniques today just end up alienating the legitimate users of the software. For example, I have some CDROM games for the kids that I cannot backup, and that really frustrates me, as the kids are incredibly rough on them. We’ve had well over 10 CDs destroyed in past several years (cracked, scratched beyond repair,etc.), but luckily they have been just the backups that we give them to use (the originals are put safely away).

    Sorry to get off topic, but I was just wondering why the need for this unique ID?

  9. #9
    Senior Member
    Join Date
    Jul 2004
    Location
    Sheffield, UK
    Posts
    694

    Default

    M$ supply some crypto stuff in their API's which can genereat a key dependent on the machines HW, I might be talking B******s but I recall seeing somethnig like it... I will try hunting or the info...

  10. #10
    Senior Member
    Join Date
    Jul 2004
    Location
    Detroit area, USA
    Posts
    119

    Default

    My brother-in-law still believes it's worth building machines from scratch and he has had no end of trouble from Microsoft's activation scheme. Since he built his latest box, compatibility issues have been dogging him, causing him to swap out different components in an effort to get a stable configuration. He's had to do several re-installs of XP, and every time he's had to phone Microsoft and manually enter the umpteen-digit key as it is read to him by a Microsoftie. For some reason, the over-the-internet registration doesn't work for him. If it weren't a necessary piece of software, he would have dropped it long ago.

    Oh, and I have no idea how to generate a unique identifier for a machine.
    Paul Kerchen

  11. #11
    Senior Member
    Join Date
    Jul 2004
    Location
    Malta
    Posts
    273

    Default

    Cas,

    Not sure if you can get something such as the NIC card's MAC address using purely Java.

    In the worst case you could create a custom C/C++ module integrated into your Java app using JNI. The C/C++ module sources would then use #define's containing the function code for each of your target platforms, say, PC, Linux, Mac or whatever.

    It might entail a little work first time round but you would effectively end up with a reusable piece of functionality.
    Nemesis

  12. #12
    Senior Member
    Join Date
    Jul 2004
    Location
    France
    Posts
    163

    Default

    A friend once said he bought several network cards from the same manufacturer, and some of them had the same MAC address.

  13. #13
    Senior Member
    Join Date
    Jul 2004
    Location
    Seattle, WA
    Posts
    623

    Default

    One company I worked at had the same problem on mac addresses on a set of cards from the same manufacturer. We had a terrible time figuring out what the problem was. I hear it happens more than you think.

  14. #14
    Moderator
    Join Date
    Jul 2004
    Location
    Kitchener, ON
    Posts
    173

    Default

    Quote Originally Posted by kerchen
    He's had to do several re-installs of XP, and every time he's had to phone Microsoft and manually enter the umpteen-digit key as it is read to him by a Microsoftie. For some reason, the over-the-internet registration doesn't work for him. If it weren't a necessary piece of software, he would have dropped it long ago.
    Necessary? pfft! Using Windows 2000 here and avoiding XP features like "randomly stop working" and "take an hour to install an update"

    You aren't really going to be able to get the same number each time princec, nor can you be 100% guaranteed it is unique afaik. Your best bet is to follow in Microsoft's footsteps and use multiple pieces of hardware to figure out some unique ID from. They put a lot of research into this and it's the best they could come up with.

    "Always get same number when install on same machine" isn't possible because any component can get swapped out at any time. The hardware in my machine now is very different from the hardware two years ago, even though it's the same computer. Can you elaborate more on what you are trying to accomplish?

  15. #15
    Senior Member
    Join Date
    Aug 2004
    Location
    Utah, USA
    Posts
    844

    Default

    I remember reading somewhere that there's a unique ID encoded into Pentium III CPUs and above. (It was something a number of eCommerce companies wanted to uniquely identify the customer's computer.) Of course this would only work on more recent Intel hardware. I don't know if AMD is doing something similar. Maybe this is why MS uses hardware configs as part of their ID.

  16. #16
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    All I want is a reasonable - not foolproof - API call that'll get me an ID number that is largely static for the duration of the machine's lifetime. A harddisk identifier would be fine. MAC address would be fine. CPU ID would be fine. I can string all the available ones together.

    Cas

  17. #17
    Senior Member
    Join Date
    Aug 2004
    Location
    Cardiff
    Posts
    116

    Default

    In C++:

    Code:
    unsigned long driveSerial = 1234;
    GetVolumeInformation("C:\\", NULL, 0, (unsigned long*)&driveSerial, NULL, NULL, NULL, 0 );
    This gets you the hard drive ID for C:

  18. #18
    Senior Member
    Join Date
    Jul 2004
    Location
    San Mateo, CA
    Posts
    359

    Default

    Here's some code to get info from the CPU - Intel/AMD
    Dont remember where I got it...

    -J.R.

    Code:
    CStdString getCpuType( )
    {
      CStdString retStr;
      char str[255];
    
      char VendorSign[13];   //We need somewhere to store our vendorstring
      unsigned long MaxEAX;  //This will be used to store the maximum EAX
                             //possible to call CPUID with.
    
    __asm {
        XOR       EAX,                        EAX
        //An efficient alternatvie to MOV EAX, 0x0
    
        CPUID
        //This instruction will load our registers with the data we need.
    
        MOV       dword ptr [VendorSign],     EBX
        //Copy the first 4 bytes in the VendorString from EBX.
    
        MOV       dword ptr [VendorSign+4],   EDX
        //Copy the next 4 bytes.
    
        MOV       dword ptr [VendorSign+8],   ECX
        //Copy the next 4 bytes.
    
        MOV       dword ptr MaxEAX,           EAX
        //EAX contains the maximum value to call CPUID with. Copy it to the
        //MaxEAX variable.
      }
      VendorSign[12]=0;  //The last character in the VendorSign can be anything.
                         //To make sure that it stops at the last character we add
                         //a zero character at the end
    
    
      retStr += VendorSign;
      sprintf( str, "%i", MaxEAX );
      retStr += str;
    
      printf("Vendor string: %s\n", VendorSign);
      printf("Maximum EAX value: %i\n", MaxEAX);
      
    
    
      if(strcmp(VendorSign, "GenuineIntel")==0) {
        Comp1[0]="FPU";   //Floating Point Unit
        Comp1[1]="VME";   //Virtual Mode Extension
        Comp1[2]="DE";    //Debugging Extension
        Comp1[3]="PSE";   //Page Size Extension
        Comp1[4]="TSC";   //Time Stamp Counter
        Comp1[5]="MSR";   //Model Specific Registers
        Comp1[6]="PAE";   //Physical Address Extesnion
        Comp1[7]="MCE";   //Machine Check Extension
        Comp1[8]="CX8";   //CMPXCHG8 Instruction
        Comp1[9]="APIC";  //On-chip APIC Hardware
        Comp1[10]="";     //Reserved
        Comp1[11]="SEP";  //SYSENTER SYSEXIT
        Comp1[12]="MTRR"; //Machine Type Range Registers
        Comp1[13]="PGE";  //Global Paging Extension
        Comp1[14]="MCA";  //Machine Check Architecture
        Comp1[15]="CMOV"; //Conditional Move Instrction
        Comp1[16]="PAT";  //Page Attribute Table
        Comp1[17]="PSE-36"; //36-bit Page Size Extension
        Comp1[18]="PSN";  //96-bit Processor Serial Number
        Comp1[19]="CLFSH"; //CLFLUSH Instruction
        Comp1[20]="";     //Reserved
        Comp1[21]="DS";   //Debug Trace Store
        Comp1[22]="ACPI"; //ACPI Support
        Comp1[23]="MMX";  //MMX Technology
        Comp1[24]="FXSR"; //FXSAVE FXRSTOR (Fast save and restore)
        Comp1[25]="SSE";  //Streaming SIMD Extensions
        Comp1[26]="SSE2"; //Streaming SIMD Extensions 2
        Comp1[27]="SS";   //Self-Snoop
        Comp1[28]="HTT";  //Hyper-Threading Technology
        Comp1[29]="TM";   //Thermal Monitor Supported
        Comp1[30]="IA-64"; //IA-64 capable
        Comp1[31]="";     //Reserved
      }
      else if(strcmp(VendorSign, "AuthenticAMD")==0) {
        Comp1[0]="FPU";   //Floating Point Unit
        Comp1[1]="VME";   //Virtual Mode Extension
        Comp1[2]="DE";    //Debugging Extension
        Comp1[3]="PSE";   //Page Size Extension
        Comp1[4]="TSC";   //Time Stamp Counter
        Comp1[5]="MSR";   //Model Specific Registers
        Comp1[6]="PAE";   //Physical Address Extesnion
        Comp1[7]="MCE";   //Machine Check Extension
        Comp1[8]="CX8";   //CMPXCHG8 Instruction
        Comp1[9]="APIC";  //On-chip APIC Hardware
        Comp1[10]="";     //Reserved
        Comp1[11]="SEP";  //SYSENTER SYSEXIT
        Comp1[12]="MTRR"; //Machine Type Range Registers
        Comp1[13]="PGE";  //Global Paging Extension
        Comp1[14]="MCA";  //Machine Check Architecture
        Comp1[15]="CMOV"; //Conditional Move Instrction
        Comp1[16]="PAT";  //Page Attribute Table
        Comp1[17]="PSE-36"; //36-bit Page Size Extension
        Comp1[18]="";     //?
        Comp1[19]="MPC";  //MultiProcessing Capable (I made this short up, correct?)
        Comp1[20]="";     //Reserved
        Comp1[21]="";     //?
        Comp1[22]="MIE";  //AMD Multimedia Instruction Extensions (I made this short up, correct?)
        Comp1[23]="MMX";  //MMX Technology
        Comp1[24]="FXSR"; //FXSAVE FXRSTOR (Fast save and restore)
        Comp1[25]="SSE";  //Streaming SIMD Extensions
        Comp1[26]="";     //?
        Comp1[27]="";     //?
        Comp1[28]="";     //?
        Comp1[29]="";     //?
        Comp1[30]="3DNowExt"; //3DNow Instruction Extensions (I made this short up, correct?)
        Comp1[31]="3DNow"; //3DNow Instructions (I made this short up, correct?)
      }
    
      unsigned long REGEAX, REGEBX, REGECX, REGEDX;
      int dFamily, dModel, dStepping, dFamilyEx, dModelEx;
      char dType[10];
      int dComp1Supported[32];
      int dBrand, dCacheLineSize, dLogicalProcessorCount, dLocalAPICID;
    
      if(MaxEAX>=1) {
      __asm {
          MOV     EAX,                    1
          CPUID
          MOV     [REGEAX],               EAX
          MOV     [REGEBX],               EBX
          MOV     [REGECX],               ECX
          MOV     [REGEDX],               EDX
        }
        dFamily=((REGEAX>>8)&0xF);
        dModel=((REGEAX>>4)&0xF);
        dStepping=(REGEAX&0xF);
    
        dFamilyEx=((REGEAX>>20)&0xFF);
        dModelEx=((REGEAX>>16)&0xF);
        switch(((REGEAX>>12)&0x7)) {
          case 0:
            strcpy(dType, "Original");
            break;
          case 1:
            strcpy(dType, "OverDrive");
            break;
          case 2:
            strcpy(dType, "Dual");
            break;
        }
    
        for(unsigned long C=1, Q=0;Q<32;C*=2, Q++) {
          dComp1Supported[Q]=(REGEDX&C)!=0?1:0;
        }
    
    
        dBrand=REGEBX&0xFF;
        dCacheLineSize=((strcmp(Comp1[19], "CLFSH")==0)&&(dComp1Supported[19]==1))?((REGEBX>>8)&0xFF)*8:-1;
        dLogicalProcessorCount=((strcmp(Comp1[28], "HTT")==0)&&(dComp1Supported[28]==1))?((REGEBX>>16)&0xFF):-1;
        dLocalAPICID=((REGEBX>>24)&0xFF); //This only works on P4 or later, must check for that in the future
    
      }
      retStr += dType;
    
      sprintf( str, "%i%i%i",dFamily, dModel, dStepping);
      retStr += str;
    
      sprintf( str, "%i%i",dFamilyEx, dModelEx);
      retStr += str; 
      
      for(unsigned long Q=0;Q<27;Q++) 
      {
        if(dComp1Supported[Q]) 
    	{
          retStr += Comp1[Q];
        }
      }
    
      
      printf("%s\n", dType);
      printf("Family %i, Model %i, Stepping %i\n", dFamily, dModel, dStepping);
      printf("Extended Family %i, Extended Model %i\n", dFamilyEx, dModelEx);
      printf("Supported flags: ");
      for(Q=0;Q<27;Q++) {
        if(dComp1Supported[Q]) {
          printf("%s ", Comp1[Q]);
        }
      }
      printf("\n");
      printf("CacheLineSize: %i\n", dCacheLineSize);
      printf("Logical processor count: %i\n", dLogicalProcessorCount);
      printf("Local APIC ID: %i\n", dLocalAPICID);
    
      return retStr;
    
    }

  19. #19
    Senior Member
    Join Date
    Aug 2004
    Location
    Cheshire, United Kingdom
    Posts
    473

    Arrow

    unsigned long driveSerial = 1234;
    GetVolumeInformation("C:\\", NULL, 0, (unsigned long*)&driveSerial, NULL, NULL, NULL, 0 );
    I tried that, it fails. It returns the number on per-partition basis so that if you re-format then the number is different. It's a pain.

    One idea I had is to locate the floppy drive serial if there is one. No-one upgrades those do they?

    Mark
    Cornutopia Games
    http://www.cornutopia.net

  20. #20
    Senior Member
    Join Date
    Jul 2004
    Location
    Sheffield, UK
    Posts
    694

    Default

    Wipeee I eventually found what I was looking for Try searching for DPAPI in google, it's m$'s crypto library that will let you create machine/user keys which you can then use for whatever. unfortuantly this would only work on windows. (unless other OS's have omething similar)

  21. #21
    Senior Member
    Join Date
    Aug 2004
    Location
    Cardiff
    Posts
    116

    Default

    Quote Originally Posted by Mark Sheeky
    I tried that, it fails. It returns the number on per-partition basis so that if you re-format then the number is different. It's a pain.

    One idea I had is to locate the floppy drive serial if there is one. No-one upgrades those do they?

    Mark
    Cornutopia Games
    http://www.cornutopia.net
    Reformatting 'C' is relatively rare - especially among genuine customers. Anyway, its one serial, as Cas says he will use multiple, the more you use - the less chance of a problem.

  22. #22
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    I definitely can't do it from Java, this is a new API call I want to add to the LWJGL so I will be able to do it

    I'm not going to use it for copy protection in my games (though someone might) - instead I want to use it as a seed for the random number generator that creates the demo configuration, so the same computer always gets the same configuration. Or mostly always.

    Cas

  23. #23
    Moderator
    Join Date
    Jul 2004
    Location
    Kitchener, ON
    Posts
    173

    Default

    Quote Originally Posted by Dom
    Reformatting 'C' is relatively rare - especially among genuine customers. Anyway, its one serial, as Cas says he will use multiple, the more you use - the less chance of a problem.
    May or may not be relevent to princec's application but some of us have multiple OSes and hence multiple drive Cs at once.

  24. #24
    Senior Member
    Join Date
    Jul 2004
    Posts
    1,216

    Default

    Quote Originally Posted by princec
    [...]
    I'm not going to use it for copy protection in my games (though someone might) - instead I want to use it as a seed for the random number generator that creates the demo configuration, so the same computer always gets the same configuration. Or mostly always.
    Hm. I would be afraid that doing so could lead to a somewhat asymmetrical distribution of configurations, because you won't have any control about the outcome. (It could be less random then you like)

    For the webstart route... I would just use muffins there.

  25. #25
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    Now it's funny you should say that, because it just dawned on me over dinner that I could use a muffin and it'd all work out peachy

    Cas

  26. #26
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    Good solutions here. I think a Webstart muffin will probably do the trick me now though.

    Cas

  27. #27
    Senior Member
    Join Date
    Jul 2004
    Posts
    1,216

    Default

    On a side note - Kevin and me are slapping a small (10-20k) muffin lib together. Should be done (~80% atm), javadoced, debugged and tested pretty soon now.

  28. #28
    Senior Member
    Join Date
    Jul 2004
    Location
    Durham, UK
    Posts
    4,873

    Default

    Nice - where will it live when it's done?

    Cas

  29. #29
    Senior Member
    Join Date
    Jul 2004
    Posts
    1,216

    Default

    That's a good question actually. Well, I intend to have a copy floating around on my webspace, but it's usual spot will be JGF (I guess). It's supposed to be a part of the upcoming new and improved webstart tutorial... so it should be hosted there, too (I mean... it's really really small ).

+ Reply to Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts