Generating Unique Application IDs in .NET

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Many times in an application, you need to generate a unique ID. In a previous article I discussed generating a fingerprint for the purposes of identifying a web or network client of our application. Today, I’ll go one step further and show methods for generating a unique ID so that your application can identify itself.

Why Use a Unique ID?

Unique IDs are not just useful for identifying people using your app.  Trust is very often a two way street, and just as you want to be sure that the client using your app is recognized by some method, clients often need to trust the application they are dealing with.

In the case of some desktop software, you might want to be sure that the application is running on the same computer that it was originally installed. This is good for the purposes of anti piracy or to simply identify that the application is running on an authorized workstation.

Whatever the reason, there are more than a handful of ways to generate an ID that your app can use based on facilities available on the actual system and or hardware your application is running on.

What Methods Are Available?

The methods that are available to use depend entirely on what systems you are running on.  For example, the finger printing code I showed in a previous article could be applied both ways, if you’re a web application you could use the same items of data available to generate an ID that you then give back to the client, which the client can then use to ID you.

The problem with this is the same as for using it to ID the client.  Should anything change on the client, then you might find yourself in a situation where the client no longer trusts you, because of something that happened at their end.

From your own side of the equation, you can simply just generate a GUID. .NET does in fact have a built in data type for this, so it’s as easy as just creating a new GUID and using it as you see fit.

What do you do if you want to tie it to a physical system, namely the system your application is currently running on? In this case the first place to look is the same place that Microsoft looks to generate operating system ID’s to protect against piracy, and that’s at the hardware.

What Hardware Can Be Used?

When it comes to what hardware can be used, what is the truth?  All of it.

Seriously.

What you actually end up using however depends very much on how much work you’re willing to put into generating your ID. For instance, most CPUs since the original first generation Pentium one (and even some before going as far back as the 486) introduced something called the ‘CPUID instruction’. This is a simple single machine code instruction that returns a unique ID and CPU type burned into every CPU at the manufacturing level.

Unfortunately, from a Windows perspective, to access this would generally mean using unmanaged code, and breaking out to raw assembler to get at it.  Not an issue for most developers who are used to doing mixed mode dev using c++ and .NET, but a little out of reach for the average web application programmer used to doing ASP.NET MVC and/or WPF.

Don’t let the above scare you though, there’s one item of hardware that’s very easy to get access to from general application code, and that’s the various networking interfaces available.

If you open up a command prompt by typing ‘cmd’ into your run box, then run ‘ipconfig’ by typing the following into the command window and pressing return:

ipconfig /all

You should get quite a screen full of text, amongst which you should see something like this:

Ethernet adapter LAN:
   Connection-specific DNS Suffix  . : xxxxxxxxxxxxxx.xxxxx.
   Description . . . . . . . . . . . : Marvell Yukon 88E8056 PCI-E Gigabit Ethernet Controller
   Physical Address. . . . . . . . . : 00-00-00-00-00-00
   DHCP Enabled. . . . . . . . . . . : No
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : ffff::fff:ffff:ffff:ffff%10(Preferred)
   IPv4 Address. . . . . . . . . . . : xxx.xxx.xxx.xxx(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : xxx.xxx.xxx.xxx
   DHCPv6 IAID . . . . . . . . . . . : 0000000000
   DHCPv6 Client DUID. . . . . . . . : 11-11-11-11-11-11-11-11-11-11-11-11-11-11
   DNS Servers . . . . . . . . . . . : xxx.xxx.xxx.xxx
   NetBIOS over Tcpip. . . . . . . . : Enabled

I’ve censored some of the details above just to protect the systems I’m typing this on, but you should in general get a similar output.

In the output above you should be able to see there’s an item called ‘Physical Address’; this is the item we’re interested in. Every network interface, no matter what its IP address (or ATM Token, Pipe address, Hub ID, etc.) has a physical hardware address, usually burned into the chips on the device itself. This address is more commonly referred to as the ‘MAC Address’ and is 99% of the time unique to the device it’s being used on.

Why only 99%?

In recent times, we’ve started building virtual network devices, and devices that have soft settings for their MAC Address, enabling them to be changed to a user supplied value. For our purposes however, most of the time you’ll not find this value gets changed (or spoofed as it’s more commonly known) unless the user of the machine is up to something they shouldn’t be.

Also, another benefit to this is that anything that uses any kind of network style interface will have to generate a MAC Address.

This often means that you can look for things like bluetooth adapters, wifi dongles and even tethered mobile phones.  Many VM systems such as ‘VM Ware’ and ‘Virtual Box’ also install pseudo network adapters that show up as a legitimate interface, so you could actually generate an ID that ties your software to the fact that one of these products are installed on the platform in question.

How Do I Read a MAC Address?

I’ve covered enough theory. At this point, you likely want to know how to read a MAC Address. Like anything in software development, there are several ways to achieve this; for the purposes of this post however, I’ll just show you the easiest.

.NET has an object in the ‘System.Net’ namespace called ‘NetworkInformation’, inside the network information class exists a static method that will obtain all the network information for anything in the system that presents a network like interface.

Calling this static function, will provide you with an array of ‘NetworkInterface’ objects, which you can then further interrogate to get the information you need.

In our case, something like the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
 
namespace MyApp
{
  public class Class1
  {
    public string GetMacAddress()
    {
      string result = string.Empty;
 
      using(List<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().ToList())
      {
        result = nics.Select(nic => nic.GetPhysicalAddress()).FirstOrDefault(mac => !string.IsNullOrEmpty(mac.ToString())).ToString();
      }
 
      return result;
    }
 
 
  }
}

What we’re doing here is to get the array of ‘NetworkInterface’ objects available, convert it to a List<T>, then ‘Using’ that list (so that we garbage collect it correctly afterwards) we use Linq to Objects to select all, then find the first one in that selection with a non null, or non empty MAC Address.

The result is a string representing the first non empty mac/physical address present in the system the app is running on.

You could further refine this by using a further check on the type and/or description of the interface object, to only look for certain adapters.

From Here…

In a future post, we’ll look at other ways you might be able to use hardware attached to a machine such as hard drive serial numbers and smart card readers, in the mean time you might want to explore the interface object, and see what other items are available that you might be able to use.

If you have any ideas for posts for this series, please reach out to me on twitter ‘@shawty_ds’ or come and find me in the Linked .NET users group (Lidnug) on the Linked-In social network and I’ll do my best to include them.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read