Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Unique computer ID

June 22, 2011 27 Comments

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

>> 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

% 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

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.

Related posts:

  1. Controlling callback re-entrancy – Callback reentrancy is a major problem for frequently-fired events. Luckily, it can easily be solved....
  2. More undocumented timing features – There are several undocumented ways in Matlab to get CPU and clock data...
  3. Matlab compiler bug and workaround – Both the Matlab compiler and the publish function have errors when parsing block-comments in Matlab m-code. ...
  4. Types of undocumented Matlab aspects – This article lists the different types of undocumented/unsupported/hidden aspects in Matlab...
  5. Matlab installation woes – Matlab has some issues when installing a new version. This post discusses some of them and how to overcome them....
  6. Docking figures in compiled applications – Figures in compiled applications cannot officially be docked since R2008a, but this can be done using a simple undocumented trick....
Compiler Java Pure Matlab
Print Print
« Previous
Next »
27 Responses
  1. Aurélien June 23, 2011 at 08:24 Reply

    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

    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. Etienne Balmes June 23, 2011 at 13:36 Reply

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

    !lmhostid -w

    !lmhostid -w

    or:

    !lmutil hostid

    !lmutil hostid

    • Donn Shull June 25, 2011 at 14:12 Reply

      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')

      [status, value] = system('lmutil lmhostid -n')

  3. Jan Simon June 26, 2011 at 19:11 Reply

    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

    !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 July 14, 2011 at 10:51 Reply

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

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

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

    BTW, great site!
    Nathan

    • Yair Altman July 14, 2011 at 11:47 Reply

      @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')

      getenv('computername')

  5. Jan Simon July 20, 2011 at 10:02 Reply

    A small change for your Java approach:
    Instead of

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

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

    this might be nicer:

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

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

    • Yair Altman July 20, 2011 at 12:06 Reply

      @Jan – I humbly stand corrected 🙂

  6. Matthias September 20, 2011 at 15:21 Reply

    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

    • Yair Altman September 20, 2011 at 15:35 Reply

      @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 November 16, 2011 at 01:24 Reply
    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

    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 March 1, 2013 at 04:10 Reply

      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);

      mac_add = a(b(end)+1:b(end)+19);

    • Xiangrui Li May 1, 2017 at 23:06 Reply

      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

      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 April 30, 2012 at 05:46 Reply

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

  9. damayi May 22, 2012 at 20:43 Reply

    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 February 20, 2013 at 07:33 Reply

    really helpful

  11. thomas February 20, 2014 at 08:50 Reply

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

    • Yair Altman February 20, 2014 at 09:23 Reply

      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 February 20, 2014 at 09:26

        @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.

      • Yair Altman February 20, 2014 at 09:29

        @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')

        system('ipconfig /all')

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

    • thomas February 20, 2014 at 09:40 Reply

      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 February 20, 2014 at 09:56

        @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{:}];

        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 February 20, 2014 at 10:09 Reply

      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 🙂

      • Yair Altman February 20, 2014 at 10:20

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

  12. Jeff E Mandel MD MS October 31, 2016 at 15:41 Reply

    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

    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 June 13, 2022 at 03:58 Reply

    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!

    • Yair Altman June 13, 2022 at 12:38 Reply

      @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
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top