For a requirement to generate per-PC license keys, I need some code which will return a stable and (near) unique key on any PC. It doesn't have to be guaranteed unique, but close. It does need to be reasonably stable though, so that a given PC always generates the same result unless the hardware is substantially changed.
This is for a Windows application, using wxWidgets but a Win32 or other option is fine.
I was thinking about MAC address but what about laptops which can routinely disable the network card in power-saving mode? I came across GetCurrentHwProfile but it doesn't quite look like what I want?
I would just go with the MAC address method; when the wireless / LAN cards are turned off they still show up in Network Connections. You should therefore still be able to get the MAC.
Consider this: Any time you'd be able to contact your webserver or whatever you're cataloging these IDs with, the user is going to have to have some form of network card available.
Oh, and you might be able to use CPU serial number of the customer's computer supports it.
One idea I had a while back for this is to use CryptProtectData as a way to identify a machine. Behind-the-scenes in that API, Microsoft has done what you're looking for. I never tested it though and I'm curious if it's actually viable.
Basically you would encode a constant magic value with CryptProtectData
with CRYPTPROTECT_LOCAL_MACHINE
, and the result is your machine ID.
If you want something a bit harder to spoof than whatever the machine itself can tell you, you'll probably need to provide a USB dongle dedicated for this purpose (not just a flash drive).
How about using the serial number of the harddisk where windows is installed?
The function GetVolumeInformation() will give you such serial number.
To access the ID assigned by the harddisk vendor instead of the ID assigned by Windows, you can use the Win32_PhysicalMedia Class.
To determine the drive where windows is installed, you could expand the variable %windir" by using the function ExpandEnvironmentStrings()
Another option, if your architecture allows, is to use UuidCreate() to generate a random GUID at installation time and save it permanently in the registry. This GUID can then be used as the ID as long as the registry remains. A new registry database is generally considered as a new installation.
A third option is to have a well-known server assigning the IDs. Upon starting up, the software could look up for the ID in the registry and if not found, would contact the server and supply it with its MAC address, hostname, harddisk serial number, Machine SID and any number of indentifyable information (keys).
The server then determines if the client is already registered or not based on the information given. The server could have a relaxed policy and for example only require most of the keys for a match, so that the mechanism would work even in the event of a complete wipe out of the registry and if part (but not all) of the hardware was replaced.
I think there no really easy and unique method so far discovered here.
- GetVolumeInformation retrieves not even close to unique ID.....
- To use any hardware serial is problematic because manufactures are not committed to supported it always and especially to keep it globally unique
- GetCurrentHwProfile retrieves GUID but it's value affected by minor! hardware changes...
- Using Product Key ... will bring U to deal with the stolen software - there lot of pirate installations over the globe.
- Creation of own GUID and preserving it under registry (in any place) will not prevent duplication by cloning of image ....
etc...
From my perspective of view the best way is combine:
Volume ID + MAC's list + Machine SID + Machine Name. And obviously manage license policy on the server side ;0)
Regards
Mickel.
For a pretty brain dead test I am using the ProductID code of the OS and the computer name - both extracted from the registry. Not really secure, but its all pretend security anyway.
edit
To answer John's question about what keys I am reading:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductID
SYSTEM\CurrentControlset\Control\ComputerName\ComputerName\ComputerName
How about using the serial number of a CPU. I remember Microsoft used to provide an api for this that would run the necessary assembler code and give you back all sorts of info about the CPU including serial number. Not sure if it'd work with AMD chips or not, I think it was intel specific.
Surely CPU Id is secure and static enough!!