Unique computer ID

It is sometimes beneficial to have a unique identifier for the system on which we are currently running. For example, if you sell software, you may wish to verify that the computer is licensed or activated. A question on CSSM today reminded me of this issue.

A trivial solution to this question is to use the built-in license function. Unfortunately, this does not work with a multi-system network/floating Matlab license, nor on deployed (compiled) systems.

While Matlab doesn’t have a built-in solution, we can use simple Java to access system information. There are several possible approaches. Here are several alternatives:

Windows SID

A Windows-specific approach is to return the Window Domain Controller’s SID (Security ID). This is a unique identifier that changes with each computer/user. Java enables direct access to this identifier, and we can run this directly in Matlab:

>> sid = get(com.sun.security.auth.module.NTSystem,'DomainSID')
sid =
S-1-5-21-292311649-1610625687-3346456317

The exact same value can also be gotten directly from the Windows Registry:

% Note: scanning HKEY_-- USERS node names is better, but Matlab's winqueryreg() can't do that...
rootkey = 'HKEY_CURRENT_-- USER';
subkey = 'Software\Microsoft\Windows\CurrentVersion\Group Policy\GroupMembership';
count = winqueryreg(rootkey,subkey,'Count');
for idx = 0 : double(count)-1   % Note: double() is needed for Matlab 6 compatibility
    val = winqueryreg(rootkey,subkey,['Group' char('0'+idx)]);
    dashes = find(val=='-');
    if length(dashes) > 4,  sid = val(1:dashes(end)-1);  break;  end   % short ids are phoney
end

This later version, although less simple than the first alternative (Java-based approach) above, has the benefit of working on old Matlab releases such as R12 (6.0) where the Java approach fails. For this reason, my getsid utility on the File Exchange uses the registry approach.

Other platforms

For non-Windows systems, both of the above approaches fail. For such platforms, we can use the Ethernet addresses of the computer’s network cards. This should be pretty unique for any practical effect:

sid = '';
ni = java.net.NetworkInterface.getNetworkInterfaces;
while ni.hasMoreElements
    addr = ni.nextElement.getHardwareAddress;
    if ~isempty(addr)
        addrStr = dec2hex(int16(addr)+128);
        sid = [sid, '.', reshape(addrStr,1,2*length(addr))];
    end
end
 
>> sid
sid = 
.89ECC872C85C.8AFE928FEDB4.8262278A1CCA.899919B50FC9

This again uses Java (which unfortunately fails on R12 aka 6.0). The benefit is that it is entirely cross-platform, working wherever Matlab runs (including Windows), on any Matlab release that supports Java (I think R13 aka 6.5 should be the earliest).

Do you have another way to generate unique identifiers? If so, please share your experience in a comment.

Categories: Java, Low risk of breaking in future versions

Tags: , ,

Bookmark and SharePrint Print

27 Responses to Unique computer ID

  1. Aurélien says:

    To limit the use of my softwares , I ask end-users the hostname of their machines or their login

    For the login for example I use the following piece of code which is cross-platform

    username = getenv('-- USERNAME'); 
    if isempty(username)
        str = '!whoami'; 
        username = deblank(evalc(str));
    end

    Then I compare the username string with what I expect to get.

    Aurélien

  2. You can use flexlm which always ships with MATLAB. Look for

    !lmhostid -w

    or:

    !lmutil hostid
    • Donn Shull says:

      Keep in mind Yair’s note that using the license manager does not work in deployed applications and may not give reliable results in MATLAB network served instances.
      The form that you can use in a function is:

      [status, value] = system('lmutil lmhostid -n')
  3. Jan Simon says:

    The harddisk ID and the creation date of the drive containing the OS are most likely unique.
    Under Windows (XP, and newer?) POWERCFG replies a list, which contains the hardware IDs of all devices, which have been connected in the past:

    !powercfg /DEVICEQUERY all_devices_verbose

    It is hard to parse the replied list, e.g. to find a specific ID of the harddisk. But if you know a ID, e.g. the vendor ID of an USB-stick, it is easy to check if this string appears anywhere in the list.

    Kind regards, Jan

  4. Nathan says:

    I don’t know how portable it is, but on Windows I use

    getHostName(java.net.InetAddress.getLocalHost());

    BTW, great site!
    Nathan

    • @Nathan – thanks for the compliment.

      Your method is actually portable (cross-platform), since it is based on generic plain-vanilla Java. Unfortunately, I’m afraid it is not very unique since it just returns the computer name, which is non-unique by definition. By the way, on Windows you can use the following much simpler method to get this computer name:

      getenv('computername')
  5. Jan Simon says:

    A small change for your Java approach:
    Instead of

    addrStr = dec2hex(int16(addr)+128);
    sid = [sid, '.', reshape(addrStr,1,2*length(addr))];

    this might be nicer:

    sid = [sid, '.', sprintf('%.2X', typecast(addr, 'uint8'))];
  6. Matthias says:

    Hi,

    for licensing I always use the MAC address of (one of) the network controllers. This address is absolutley unique for each network device worldwide.

    The only way to access this I know of is using C/C++ compiled to a *.dll which can then be called from MATLAB using calllib

    If interested I can post the code from the function to access the device.

    And yes, this is a great site, learned a lot about Java in MATLAB and using lots of it.
    Keep up Yair!

    Matthias

    • @Matthias – thanks :-) The code I posted above does exactly what you say, specifying the MAC addresses of all the computer’s network controllers. Please take a look – it’s actually quite simple and does not require any DLL, so it works on both Windows and non-Windows platforms.

  7. Jayveer says:
    switch computer('arch')
        case {'maci','maci64'}
            [~,a]=system('ifconfig');
            c=strfind(a,'en0');if ~isempty(c),a=a(c:end);end
            c=strfind(a,'en1');if ~isempty(c),a=a(1:c-1);end
            % find the mac address
            b=strfind(a,'ether');
            mac_add=a(1,b(1)+6:b(1)+22);
        case {'win32','win64'}
            [~,a]=system('getmac');b=strfind(a,'=');
            mac_add=a(b(end):b(end)+19);
        case {'glnx86','glnxa64'}
            [~,a]=system('ifconfig');b=strfind(a,'Ether');
            mac_add=a(1,b(1)+17:b(1)+33);
        otherwise,mac_add=[];
    end
    • Sami says:

      Thanks for the code, it’s very helpful, however in the {‘win32′,’win64’} i had to add “+1” to get the right MAC address. without the preceding “=” :

      mac_add = a(b(end)+1:b(end)+19);
    • Xiangrui Li says:

      Here is my practice for regexp. For all OS, always take the first mac_add pattern in the string output.

      if ispc
          [~, a] = system('getmac');
          mac_add = regexp(a, '([0-9A-F]{2}-){5}[0-9A-F]{2}', 'match', 'once');
      elseif isunix % OSX and Linux
          [~, a] = system('ifconfig');
          mac_add = regexp(a, '([0-9a-f]{2}:){5}[0-9a-f]{2}', 'match', 'once');
      else
          mac_add = [];
      end
  8. itrentals says:

    This is a really good guide, especially for those developing software (like you say) who are fearful that it will get copied.

  9. damayi says:

    SID is not an absolutely secure way to protect your license.
    There are many software tool which can modify computer sid, such as NewSid software.

  10. Priti says:

    really helpful

  11. thomas says:

    How unique is SID? Can be there 2 identical SIDs in the world?

    • Thomas – of course: any computer-generated id can be spoofed and hacked. You can never fully protect yourself from this. But if you’re looking at normal legal behavior, then it should be unique for any practical purposes.

    • thomas says:

      @Yair – sorry, I meant not SID but that second method, where sid = .89ECC872C85C.8AFE928FEDB4.8262278A1CCA.899919B50FC9

      Is it the MAC address? Because MAC address has 12 digits. My SID (this 48 digits long) is different from my MAC. Thanks.

    • @Thomas – in this case you have 4 separate MAC addresses, from 4 separate network devices. Run the following in your Matlab command prompt to see the list (look at the “Physical Address” rows):

      system('ipconfig /all')

      This again is only unique if the user does not fool around with the MACs…

    • thomas says:

      Yes, they are different, this is why i am confused a bit. The SID method gives .D6CDDF05903C.8888888600000000.8888888600000000.8888888600000000
      IPconfig says:
      50-E5-49-50-53-7A (this is the ethernet adapter)
      00-00-00-00-00-00-00-E0
      00-00-00-00-00-00-00-E0
      00-00-00-00-00-00-00-E0

    • Yair Altman says:

      @Thomas – it’s simply a different representation of the data. Here’s an implementation that should return more legible results:

      ni = java.net.NetworkInterface.getNetworkInterfaces;
      macStrs = {};
      while ni.hasMoreElements
          macAddr = ni.nextElement.getHardwareAddress;
          if ~isempty(macAddr)
              macAddrStr = ['.' sprintf('%02X',mod(int16(macAddr),256))];
              macStrs{end+1} = macAddrStr; %#ok
          end
      end
      macStrs = sort(unique(macStrs));
      sid = [macStrs{:}];
    • thomas says:

      oh, i see.. the new method indeed gives .00000000000000E0.50E54950537A :)

      thank you for your clarification. could you please delete my mac addresses, they were not intended to go public :)

    • Next time don’t post on a public blog something that you don’t want to appear publicly!

  12. Jeff E Mandel MD MS says:

    Newer Macs have a hardware UUID. Note that Apple won’t allow a program that uses this in the App Store, but this probably won’t affect too many people writing deployed applications. Here is a little routine that accesses the system profile using the system_profiler command.

    function profile = getMacProfile
    % Retrieves all of the information from the OSX system profile and returns
    % it in a structure, replacing spaces with underscores in the names and
    % removing the attributes in parentheses.
     
    [~,out]=system('system_profiler SPHardwareDataType');
    theLines = splitlines(out);
    for i = 1:length(theLines)
        if ~isempty(theLines{i})
            try
                c=strsplit(theLines{i},': ');
                if length(c) == 2
                    d=strip(c{1});
                    e=regexprep(d,' \(.*\)','');
                    tag =strrep(e, ' ','_');
                    profile.(tag) = c{2};
                end
            catch
                % In case Apple comes up with a new entry
                disp(theLines{i});
            end
        end
    end

    The UDID (unique device ID) is returned in profile.Hardware_UUID. This is probably more reliable than the MAC address of EN0.

  13. Mitchell says:

    Great post! I’m not very familiar with the network interfaces being referenced here, but it seems like the java-based cross-platform method concatenates all network interfaces. Does that mean that the SID returned by this method will change if a network interface is added or removed? Is it even possible to add or remove this type of network interface? Thanks!

    • @Mitchell – in most cases the user wants a single string identifier for the computer, that uniquely identifies it with a distinct fingerprint that is different from any other computer. The network interface (MAC) addresses are reported by the operating system, and naturally change when you add or remove a network card or adapter. It is up to you to decide which of the MAC addresses should be included in the fingerprint: if you include all of them, it certainly makes your fingerprint unique, but might include addresses that change frequently (e.g. VPN, WiFi, or virtual interfaces). On the other hand, if you ignore too many interfaces, your SID might be easier to spoof. Different operating systems have different ways of handling network interface MAC addresses, and you should consider this as well. For example, Windows and Linux addresses are pretty stable, but MacOS constantly changes the addresses when you connect/disconnect a network interface. MacOS also changes the computer’s hostname automatically, without any user approval, which is a PITA. In short, having a stable, unique SID that is less prone to spoofing requires some thought. If you need my assistance with this, please contact me privately (altmany at gmail).

Leave a Reply

Your email address will not be published. Required fields are marked *