How to get a unique computer identifier in Java (like disk ID or motherboard ID)?

JavaUniqueidentifierUuid

Java Problem Overview


I'd like to get an id unique to a computer with Java, on Windows, MacOS and, if possible, Linux. It could be a disk UUID, motherboard S/N...

Runtime.getRuntime().exec can be used (it is not an applet).

Ideas?

Java Solutions


Solution 1 - Java

The problem with MAC address is that there can be many network adapters connected to the computer. Most of the newest ones have two by default (wi-fi + cable). In such situation one would have to know which adapter's MAC address should be used. I tested MAC solution on my system, but I have 4 adapters (cable, WiFi, TAP adapter for Virtual Box and one for Bluetooth) and I was not able to decide which MAC I should take... If one would decide to use adapter which is currently in use (has addresses assigned) then new problem appears since someone can take his/her laptop and switch from cable adapter to wi-fi. With such condition MAC stored when laptop was connected through cable will now be invalid.

For example those are adapters I found in my system:

lo MS TCP Loopback interface
eth0 Intel(R) Centrino(R) Advanced-N 6205
eth1 Intel(R) 82579LM Gigabit Network Connection
eth2 VirtualBox Host-Only Ethernet Adapter
eth3 Sterownik serwera dostepu do sieci LAN Bluetooth

Code I've used to list them:

Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
while (nis.hasMoreElements()) {
    NetworkInterface ni = nis.nextElement();
    System.out.println(ni.getName() + " " + ni.getDisplayName());
}

From the options listen on this page, the most acceptable for me, and the one I've used in my solution is the one by @Ozhan Duz, the other one, similar to @finnw answer where he used JACOB, and worth mentioning is com4j - sample which makes use of WMI is available here:

ISWbemLocator wbemLocator = ClassFactory.createSWbemLocator();
ISWbemServices wbemServices = wbemLocator.connectServer("localhost","Root\\CIMv2","","","","",0,null);
ISWbemObjectSet result = wbemServices.execQuery("Select * from Win32_SystemEnclosure","WQL",16,null);
for(Com4jObject obj : result) {
    ISWbemObject wo = obj.queryInterface(ISWbemObject.class);
    System.out.println(wo.getObjectText_(0));
}

This will print some computer information together with computer Serial Number. Please note that all classes required by this example has to be generated by maven-com4j-plugin. Example configuration for maven-com4j-plugin:

<plugin>
    <groupId>org.jvnet.com4j</groupId>
    <artifactId>maven-com4j-plugin</artifactId>
    <version>1.0</version>
    <configuration>
        <libId>565783C6-CB41-11D1-8B02-00600806D9B6</libId>
        <package>win.wmi</package>
        <outputDirectory>${project.build.directory}/generated-sources/com4j</outputDirectory>
    </configuration>
    <executions>
        <execution>
            <id>generate-wmi-bridge</id>
            <goals>
                <goal>gen</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Above's configuration will tell plugin to generate classes in target/generated-sources/com4j directory in the project folder.

For those who would like to see ready-to-use solution, I'm including links to the three classes I wrote to get machine SN on Windows, Linux and Mac OS:

Solution 2 - Java

The OSHI project provides platform-independent hardware utilities.

Maven dependency:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>LATEST</version>
</dependency>

For instance, you could use something like the following code to identify a machine uniquely:

import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.ComputerSystem;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;

class ComputerIdentifier
{
	static String generateLicenseKey()
	{
		SystemInfo systemInfo = new SystemInfo();
		OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
		HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
		CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
		ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();

		String vendor = operatingSystem.getManufacturer();
		String processorSerialNumber = computerSystem.getSerialNumber();
		String processorIdentifier = centralProcessor.getIdentifier();
		int processors = centralProcessor.getLogicalProcessorCount();

		String delimiter = "#";

		return vendor +
				delimiter +
				processorSerialNumber +
				delimiter +
				processorIdentifier +
				delimiter +
				processors;
	}

	public static void main(String[] arguments)
	{
		String identifier = generateLicenseKey();
		System.out.println(identifier);
	}
}

Output for my machine:

Microsoft#57YRD12#Intel64 Family 6 Model 60 Stepping 3#8

Your output will be different since at least the processor serial number will differ.

Solution 3 - Java

It is common to use the MAC address is associated with the network card.

The address is available in Java 6 through through the following API:

Java 6 Docs for Hardware Address

I haven't used it in Java, but for other network identification applications it has been helpful.

Solution 4 - Java

What do you want to do with this unique ID? Maybe you can do what you want without this ID.

The MAC address maybe is one option but this is not an trusted unique ID because the user can change the MAC address of a computer.

To get the motherboard or processor ID check on this link.

Solution 5 - Java

On Windows only, you can get the motherboard ID using WMI, through a COM bridge such as JACOB.

Example:

import java.util.Enumeration;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;

public class Test {
    public static void main(String[] args) {
        ComThread.InitMTA();
        try {
            ActiveXComponent wmi = new ActiveXComponent("winmgmts:\\\\.");
            Variant instances = wmi.invoke("InstancesOf", "Win32_BaseBoard");
            Enumeration<Variant> en = new EnumVariant(instances.getDispatch());
            while (en.hasMoreElements())
            {
                ActiveXComponent bb = new ActiveXComponent(en.nextElement().getDispatch());
                System.out.println(bb.getPropertyAsString("SerialNumber"));
                break;
            }
        } finally {
            ComThread.Release();
        }
    }
}

And if you choose to use the MAC address to identify the machine, you can use WMI to determine whether an interface is connected via USB (if you want to exclude USB adapters.)

It's also possible to get a hard drive ID via WMI but this is unreliable.

Solution 6 - Java

Be careful when using the MAC address as an identifier. I've experienced several gotchas:

  1. On OS X, ethernet ports that are not active/up do not show up in the NetworkInterface.getNetworkInterfaces() Enumeration.
  2. It's insanely easy to change a MAC address on cards if you've got appropriate OS privileges.
  3. Java has a habit of not correctly identifying "virtual" interfaces. Even using the NetworkInterface.isVirtual() won't always tell you the truth.

Even with the above issues, I still think it's the best pure Java approach to hardware locking a license.

Solution 7 - Java

Not Knowing all of your requirements. For example, are you trying to uniquely identify a computer from all of the computers in the world, or are you just trying to uniquely identify a computer from a set of users of your application. Also, can you create files on the system?

If you are able to create a file. You could create a file and use the creation time of the file as your unique id. If you create it in user space then it would uniquely identify a user of your application on a particular machine. If you created it somewhere global then it could uniquely identify the machine.

Again, as most things, How fast is fast enough.. or in this case, how unique is unique enough.

Solution 8 - Java

I think you should look at this link ... you can make a mixed key using several identifiers such as mac+os+hostname+cpu id+motherboard serial number.

Solution 9 - Java

The usage of MAC id is most easier way if the task is about logging the unique id a system.

the change of mac id is though possible, even the change of other ids of a system are also possible is that respective device is replaced.

so, unless what for a unique id is required is not known, we may not be able to find an appropriate solution.

However, the below link is helpful extracting mac addresses. http://www.stratos.me/2008/07/find-mac-address-using-java/

Solution 10 - Java

For identifying a windows machine uniquely. Make sure when you use wmic to have a strategy of alternative methods. Since "wmic bios get serialnumber" might not work on all machines, you might need to have additional methods:

# Get serial number from bios
wmic bios get serialnumber
# If previous fails, get UUID
wmic csproduct get UUID
# If previous fails, get diskdrive serialnumber
wmic DISKDRIVE get SerialNumber

Resources: The Best Way To Uniquely Identify A Windows Machine http://www.nextofwindows.com/the-best-way-to-uniquely-identify-a-windows-machine/

Solution 11 - Java

In the java programs I have written for release I used the motherboard serial number (which is what I beleive windows use); however, this only works on windows as my function creates a temporary VB script which uses the WMI to retrieve the value.

public static String getMotherboardSerial() {
	  String result = "";
	    try {
	      File file = File.createTempFile("GetMBSerial",".vbs");
	      file.deleteOnExit();
	      FileWriter fw = new FileWriter(file);

	      String vbs =
	         "Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n"
	        + "Set colItems = objWMIService.ExecQuery _ \n"
	        + "   (\"Select * from Win32_ComputerSystemProduct\") \n"
	        + "For Each objItem in colItems \n"
	        + "    Wscript.Echo objItem.IdentifyingNumber \n"
	        + "Next \n";

	      fw.write(vbs);
	      fw.close();
	      Process gWMI = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
	      BufferedReader input = new BufferedReader(new InputStreamReader(gWMI.getInputStream()));
	      String line;
	      while ((line = input.readLine()) != null) {
	         result += line;
	         System.out.println(line);
	      }
	      input.close();
	    }
	    catch(Exception e){
	        e.printStackTrace();
	    }
	    result = result.trim();
	    return result;
	  }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGohuView Question on Stackoverflow
Solution 1 - JavaBartosz FirynView Answer on Stackoverflow
Solution 2 - JavaBullyWiiPlazaView Answer on Stackoverflow
Solution 3 - Javanickk_canView Answer on Stackoverflow
Solution 4 - JavaPedro GhilardiView Answer on Stackoverflow
Solution 5 - JavafinnwView Answer on Stackoverflow
Solution 6 - JavaJason NicholsView Answer on Stackoverflow
Solution 7 - JavasindriView Answer on Stackoverflow
Solution 8 - JavaMichel Gokan KhanView Answer on Stackoverflow
Solution 9 - JavaVamsyView Answer on Stackoverflow
Solution 10 - JavaBasil MusaView Answer on Stackoverflow
Solution 11 - JavaCharles EddyView Answer on Stackoverflow