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

11

69

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?

Sidwel answered 31/12, 2009 at 19:15 Comment(4)
Is this for an anti-piracy scheme?Scutt
probably gonna be a JNI call, nothing native javaMulticolor
Yes it's for something like anti-piracy scheme, to identify a computer.Sidwel
Anything which can be run via exec() can be replaced. All the user of the machine needs to do is create a program which always returns the expected result. This is just a matter of taking a dump from the working machine and write a program which outputs the same thing (from a file for example)Exclusion
A
23

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.

Attenweiler answered 31/12, 2009 at 19:31 Comment(5)
I've think about it, but when the network card isn't connected, i can't get any MAC addressSidwel
It's also possible for the user to switch network cards. On some laptops, when running off battery, the (wired) Ethernet card is disabled to save battery power, and is thus not visible to the operating system.Cloak
And do not forget that one does not even need to change the network card in order to spoof MAC: aboutlinux.info/2005/09/how-to-change-mac-address-of-your.htmlTinsley
This isn't really doable for me, since it requires root on linux.Masjid
I tried using MAC address on virtual machines, and found it just wasn't stable enough. Unless you can guarantee stable mac addresses across VM moves and reboots, using the MAC address as a machine identifier will cause you problems. See the answer below from Bartosz Fiyrn for a better approachTifanie
U
54

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:

Upperclassman answered 17/10, 2012 at 16:42 Comment(1)
On Windows Nano Server 2016 the format is "SerialNumber = xxx". The sample code will return ever "=" as serial number. On other Windows installation it works for me.Evers
R
38

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#58YRD42#Intel64 Family 6 Model 60 Stepping 3#8

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

Romantic answered 8/6, 2016 at 14:17 Comment(2)
Just to note, some of these operations require root access depending on your OS. Might be a limiting factorCapitalize
@Capitalize What operations and on what OSs?Raman
A
23

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.

Attenweiler answered 31/12, 2009 at 19:31 Comment(5)
I've think about it, but when the network card isn't connected, i can't get any MAC addressSidwel
It's also possible for the user to switch network cards. On some laptops, when running off battery, the (wired) Ethernet card is disabled to save battery power, and is thus not visible to the operating system.Cloak
And do not forget that one does not even need to change the network card in order to spoof MAC: aboutlinux.info/2005/09/how-to-change-mac-address-of-your.htmlTinsley
This isn't really doable for me, since it requires root on linux.Masjid
I tried using MAC address on virtual machines, and found it just wasn't stable enough. Unless you can guarantee stable mac addresses across VM moves and reboots, using the MAC address as a machine identifier will cause you problems. See the answer below from Bartosz Fiyrn for a better approachTifanie
A
12

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.

Attwood answered 31/12, 2009 at 19:36 Comment(0)
A
9

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.

Ambrotype answered 1/1, 2010 at 14:11 Comment(0)
A
9

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.

Apothegm answered 1/3, 2010 at 17:21 Comment(0)
T
8

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.

Terce answered 1/1, 2010 at 14:32 Comment(0)
G
2

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.

Ghetto answered 31/12, 2009 at 20:14 Comment(3)
Links which you placed behind cpuid/moboserial describes Windows-specific ways. This isn't crossplatform.Santee
in linux you can get hdd serial number using this command : hdparm -i /dev/sda1 | awk '/SerialNo=/{print $NF}' ( just recognize OS and try different methods ) you can find MB serial number using lshw commandGhetto
And do not expect antiviruses to allow strange vbs scripts appearing on your hard drive. Most of them will immediately block the file, before you will have a chance to execute it.Tinsley
Y
1

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/

Yt answered 29/5, 2012 at 7:6 Comment(0)
D
1

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/

Duumvir answered 11/5, 2015 at 15:17 Comment(0)
A
0

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;
      }
Amaliaamalie answered 2/1, 2014 at 0:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.