6

SCENARIO


I would like to learn, in C# or VB.NET, how to generate a Hardware Id. based on the same methodology Microsoft developers does for that.

First of all before continue I must advertise this question is a better specific different question derivated from this other question: Get Hardware IDs like Microsoft does

And the basic concerns for the creation of a Microsoft's HWID, which is based on the SMBIOS table, are described in the answers of that question linked above, and more deeply here: Specifying Hardware IDs for a Computer

And my reason for trying to reproduce their methodology is just to follow a professional standard guidelines about how to do things in the right way: Microsoft's way.

PROBLEM


Since getting the SMBIOS table from managed .NET seems a impossible/not implemented task, and also I can't find any demostrative usage example of the Win32 function: GetSystemFirmwareTable, and anyways the fields parsing of a SMBIOS table it seems a real nightmare that is too much work for one single dev. ...because I suspect a working parser algorithm would need to be maintained/updated from short time to time: SMBIOS version history

...Then I assumed all that, and I choose to use the WMI classes to reproduce with limitations (SMBIOS fields that WMI doesn't expose or always are null using WMI) all what I could reproduce from the original concepts of Microsoft's HWID implementation.

To try start reproducing what Microsoft does, I attempted to start generating the HWID that just takes one field: the SMBIOS manufacturer.

My problem is that I'm doing something wrong and I don't know exactly what it could be...

So, the problems I noticed with my code:

  • My resulting SHA-1 string differs from the GUID that is built with the SHA-1 that is generated using the ComputerHardwareIds.exe tool contained in the WDK/SDK: ComputerHardwareIds specifications

(the basics for those HWID creation are explained in the urls that I linked inside the 'SCENARIO' section of this question, I insist)

  • My resulting SHA-1 string is 40 char. length. The System.GUID structure doesns't expects a string of this length, neither accepts the raw Byte-Array data of my computed SHA-1.

  • @Richard Hughes he said here:

You then need to use a type 5 (SHA-1) UUID generation scheme with 70ffd812-4c7f-4c7d-0000-000000000000 as the namespace

...But I admit I don't understand what he means about using a namespace for a cypher?. I'm probably missing that detail when building my SHA-1 string. I tried to analyze the members of the SHA1CryptoServiceProvider class in search for some property where to specify a namespace... nothing found.

This is the code I'm using, where I hardcoded the manufacturer string retrieval just to simplify things:

C# sample:

string manufacturer = "American Megatrends Inc.";
byte[] charBuff = Encoding.Unicode.GetBytes(manufacturer); // UTF-16
byte[] hashBuff = null;
string hashStr = null;

using (SHA1CryptoServiceProvider cypher = new SHA1CryptoServiceProvider()) {
    hashBuff = cypher.ComputeHash(charBuff);
    hashStr = BitConverter.ToString(hashBuff).Replace("-", ""); // Same string conversion methodology employed in a MSDN article.
}
Debug.WriteLine("SHA-1=\"{0}\"", hashStr); // SHA-1="0E74E534EE9F1985AE173C640302F58121190593" 

Guid guid = new Guid(hashBuff); // System.ArgumentException: 'Byte array for GUID must be exactly 16 bytes long.'

VB.NET sample:

Dim manufacturer As String = "American Megatrends Inc."
Dim charBuff As Byte() = Encoding.Unicode.GetBytes(manufacturer) ' UTF-16
Dim hashBuff As Byte()
Dim hashStr As String

Using cypher As New SHA1CryptoServiceProvider
    hashBuff = cypher.ComputeHash(charBuff)
    hashStr = BitConverter.ToString(hashBuff).Replace("-", "") ' Same string conversion methodology employed in a MSDN article.
End Using
Debug.WriteLine("SHA-1=""{0}""", hashStr) ' SHA-1="0E74E534EE9F1985AE173C640302F58121190593"

Dim guid As New Guid(hashBuff) ' System.ArgumentException: 'Byte array for GUID must be exactly 16 bytes long.'

The expected resulting GUID would be the same GUID that the ComputerHardwareIds.exe tool generates:

{035a20a6-fccf-5040-bc3e-b8b794c57f52} <- Manufacturer

QUESTION


Well, just... what I need and how can I fix my code to get the expected result?.

ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • 1
    Read https://stackoverflow.com/a/28776880/1744164 for namespace and SHA-1 hash to UUID – Sir Rufo Aug 01 '17 at 08:18
  • @Sir Rufo Thankyou. So... in theory I have to concatenate the namespace with the manufacturer string (that is: " 70ffd812-4c7f-4c7d-0000-000000000000" + "American Megatrends Inc."), hash the concatenation string as normally, and then take the 160 bits from SHA1 and convert it into 128 bits of a UUID?. I'm lost with that bits conversion, the pseudocode given by the author is a little bit confusing for me, concretely this part: `Copy(hash, result, 16)` what should be that 16, an offset, a base16/Hex. indication?, I don't know, but I'm trying different things while writting this comment. – ElektroStudios Aug 01 '17 at 08:56
  • Well, hash is a byte array and 16 bytes are (16*8=) 128 bits – Sir Rufo Aug 01 '17 at 09:28
  • But the `SHA1CryptoServiceProvider.ComputeHash()` function generates a buffer of 20 byte length... that is,160 bits. I don't understand the magic to apply in the bits conversion to convert those 20 bytes to 16 bytes. Thankyou anyways of course!! – ElektroStudios Aug 01 '17 at 09:37
  • 1
    There is no *conversion* - just take the first 16 bytes from the 20 bytes – Sir Rufo Aug 01 '17 at 09:52
  • Now I did it, but I'm getting a different GUID than Microsoft's one :( – ElektroStudios Aug 01 '17 at 10:19
  • You have to know, which encoding Microsoft is using to get the bytes from the strings. Try some of them starting with UTF8 - I just read Richard Hughes answer where he states that UTF-16 is the encoding – Sir Rufo Aug 01 '17 at 10:27
  • `I don't understand what he means about using a namespace for a cypher` sounds like a *deterministic GUID* as I mentioned in the first version of this. If you think you know the namespace, its not that hard to test. – Ňɏssa Pøngjǣrdenlarp Aug 01 '17 at 14:43
  • 1
    *deterministic GUID* == [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) But it doesnt seem to work - using the simplest version - Manufacturer name with that namespace doesnt result in the ID the CLI produces – Ňɏssa Pøngjǣrdenlarp Aug 01 '17 at 15:01

0 Answers0