I'm working on a Metro app written in C# and need a way to uniquely identify a device. I found the ASHWID in the documentation which looks great. The code suggested is as follows:
HardwareToken token = HardwareIdentification.GetPackageSpecificToken(null);
IBuffer hardwareId = token.Id;
IBuffer signature = token.Signature;
IBuffer certificate = token.Certificate;
The problem is, how do I turn that IBuffer into a string which I can use?
After a lot of hunting through suggestions which were actually in JS or C++ I finally found an answer!
private string GetHardwareId()
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
return BitConverter.ToString(bytes);
}
Thanks go to this blog - http://bartwullems.blogspot.co.uk/2012/09/windows-8-uniquely-identifying-device.html
This should work as well, but I don't have Windows 8 to test with...
private string GetHardwareId()
{
return BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray());
}
And if you call it more than once, you might want to stick it in a Lazy<T>
private static Lazy<string> _hardwareId = new Lazy<string>(() => BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray()), true);
public string HardwareId()
{
return _hardwareId.Value;
}
Or just make it static if you know it will always be called:
public static readonly string HardwareId = BitConverter.ToString(Windows.System.Profile.HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray()));
You can use HardwareIdentification.GetPackageSpecificToken(null)
, see http://msdn.microsoft.com/en-us/library/windows/apps/jj553431.aspx
That function gives you a lot of information, that you can filter as you like. For example:
public static string GetMachineId()
{
var hardwareToken =
HardwareIdentification.GetPackageSpecificToken(null).Id.ToArray();
var count = hardwareToken.Length / 4;
ulong id = 0ul;
for (int i = 0; i < count; i++)
{
switch (BitConverter.ToUInt16(hardwareToken, i * 4))
{
case 1:
// processor
case 2:
// memory
case 9:
// system BIOS
id = (id << 12) ^ BitConverter.ToUInt16(hardwareToken, i * 4 + 2);
break;
}
}
return Convert.ToBase64String(BitConverter.GetBytes(id));
}
However, bear in mind that this function, and the underlying API, cannot guarantee absolute uniqueness across all the machines connected to the internet. You would typically combine this with information about the user.
Another option is to generate and store a GUID in local (non-roaming) storage, and use that as your machine id. Depending in you exact needs, this may be a better solution.
For a guid id you can do the following as an extension to the above answer
private Guid GetHardwareId()
{
var token = HardwareIdentification.GetPackageSpecificToken(null);
var hardwareId = token.Id;
var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId);
byte[] bytes = new byte[hardwareId.Length];
dataReader.ReadBytes(bytes);
byte[] deviceId = new byte[16];
Array.Copy((byte[])bytes, deviceId, deviceId.Length);
return new Guid(deviceId);
}