From e02daae2670472a4f2d84dac47d43ac6b7907aad Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Sun, 28 Mar 2021 17:08:26 +0200 Subject: [PATCH 1/2] Hash Windows and Mac machine fingerprints. Now all the fingerprints are hashed. This has the following benefits: * It doesn't expose raw system IDs. The actual ID is hashed with a value unique to Vircadia, so that it doesn't match any other identifier. * It should be more future-proof. Apple doesn't promise that the platform ID will have any particular format. The hashing means it doesn't matter if it stops being a valid UUID at some point. --- libraries/networking/src/FingerprintUtils.cpp | 96 ++++++++++--------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp index 83a4f19703..d122b7c1f6 100644 --- a/libraries/networking/src/FingerprintUtils.cpp +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -37,7 +37,8 @@ static const QString FALLBACK_FINGERPRINT_KEY = "fallbackFingerprint"; QUuid FingerprintUtils::_machineFingerprint { QUuid() }; QString FingerprintUtils::getMachineFingerprintString() { - QString uuidString; + QCryptographicHash hash(QCryptographicHash::Keccak_256); + #ifdef Q_OS_LINUX // As per the documentation: // https://man7.org/linux/man-pages/man5/machine-id.5.html @@ -45,8 +46,6 @@ QString FingerprintUtils::getMachineFingerprintString() { // we use the machine id as a base, but add an application-specific key to it. // If machine-id isn't available, we try hardware networking devices instead. - QCryptographicHash hash(QCryptographicHash::Keccak_256); - QFile machineIdFile("/etc/machine-id"); if (!machineIdFile.open(QIODevice::ReadOnly | QIODevice::Text)) { // No machine ID, probably no systemd. @@ -58,7 +57,7 @@ QString FingerprintUtils::getMachineFingerprintString() { if (netDevicesInfo.empty()) { // Let getMachineFingerprint handle this contingency qCWarning(networking) << "Failed to find any hardware networking devices"; - return ""; + return QUuid().toString(); } for(auto& fileInfo : netDevicesInfo) { @@ -84,6 +83,51 @@ QString FingerprintUtils::getMachineFingerprintString() { hash.addData(data); } +#endif //Q_OS_LINUX + +#ifdef Q_OS_MAC + io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); + CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); + IOObjectRelease(ioRegistryRoot); + hash.addData(QString::fromCFString(uuidCf).toUtf8()); + CFRelease(uuidCf); +#endif //Q_OS_MAC + +#ifdef Q_OS_WIN + HKEY cryptoKey; + bool success = false; + + // try and open the key that contains the machine GUID + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &cryptoKey) == ERROR_SUCCESS) { + DWORD type; + DWORD guidSize; + + const char* MACHINE_GUID_KEY = "MachineGuid"; + + // try and retrieve the size of the GUID value + if (RegQueryValueEx(cryptoKey, MACHINE_GUID_KEY, NULL, &type, NULL, &guidSize) == ERROR_SUCCESS) { + // make sure that the value is a string + if (type == REG_SZ) { + // retrieve the machine GUID and return that as our UUID string + std::string machineGUID(guidSize / sizeof(char), '\0'); + + if (RegQueryValueEx(cryptoKey, MACHINE_GUID_KEY, NULL, NULL, + reinterpret_cast(&machineGUID[0]), &guidSize) == ERROR_SUCCESS) { + hash.addData(QString::fromStdString(machineGUID).toUtf8()); + success = true; + } + } + } + + RegCloseKey(cryptoKey); + } + + if (!success) { + // Let getMachineFingerprint handle this contingency + return QUuid().toString(); + } +#endif //Q_OS_WIN + // Makes this hash unique to us hash.addData("Vircadia"); @@ -104,7 +148,7 @@ QString FingerprintUtils::getMachineFingerprintString() { // So we have to turn it into: // {1b1b9d6d-45c2-473b-ac13-dc3011ff58d6} - uuidString = result.toHex(); + QString uuidString = result.toHex(); uuidString.insert(20, '-'); uuidString.insert(16, '-'); uuidString.insert(12, '-'); @@ -112,49 +156,9 @@ QString FingerprintUtils::getMachineFingerprintString() { uuidString.prepend("{"); uuidString.append("}"); - qCDebug(networking) << "Linux machine fingerprint:" << uuidString; -#endif //Q_OS_LINUX - -#ifdef Q_OS_MAC - io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); - CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); - IOObjectRelease(ioRegistryRoot); - uuidString = QString::fromCFString(uuidCf); - CFRelease(uuidCf); - qCDebug(networking) << "Mac serial number: " << uuidString; -#endif //Q_OS_MAC - -#ifdef Q_OS_WIN - HKEY cryptoKey; - - // try and open the key that contains the machine GUID - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &cryptoKey) == ERROR_SUCCESS) { - DWORD type; - DWORD guidSize; - - const char* MACHINE_GUID_KEY = "MachineGuid"; - - // try and retrieve the size of the GUID value - if (RegQueryValueEx(cryptoKey, MACHINE_GUID_KEY, NULL, &type, NULL, &guidSize) == ERROR_SUCCESS) { - // make sure that the value is a string - if (type == REG_SZ) { - // retrieve the machine GUID and return that as our UUID string - std::string machineGUID(guidSize / sizeof(char), '\0'); - - if (RegQueryValueEx(cryptoKey, MACHINE_GUID_KEY, NULL, NULL, - reinterpret_cast(&machineGUID[0]), &guidSize) == ERROR_SUCCESS) { - uuidString = QString::fromStdString(machineGUID); - } - } - } - - RegCloseKey(cryptoKey); - } - -#endif //Q_OS_WIN + qCDebug(networking) << "Final machine fingerprint:" << uuidString; return uuidString; - } QUuid FingerprintUtils::getMachineFingerprint() { From 2de61898e116d78210744a7f006d12a88720c74d Mon Sep 17 00:00:00 2001 From: Dale Glass Date: Thu, 1 Apr 2021 23:41:37 +0200 Subject: [PATCH 2/2] Review style fixes --- libraries/networking/src/FingerprintUtils.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/FingerprintUtils.cpp b/libraries/networking/src/FingerprintUtils.cpp index d122b7c1f6..cab8cde832 100644 --- a/libraries/networking/src/FingerprintUtils.cpp +++ b/libraries/networking/src/FingerprintUtils.cpp @@ -32,6 +32,18 @@ #include #endif //Q_OS_MAC +// Number of iterations to apply to the hash, for stretching. +// The number is arbitrary and has the only purpose of slowing down brute-force +// attempts. The number here should be low enough not to cause any trouble for +// low-end hardware. +// +// Changing this results in different hardware IDs being computed. +static const int HASH_ITERATIONS = 65535; + +// Salt string for the hardware ID, makes our IDs unique to our project. +// Changing this results in different hardware IDs being computed. +static const QByteArray HASH_SALT{"Vircadia"}; + static const QString FALLBACK_FINGERPRINT_KEY = "fallbackFingerprint"; QUuid FingerprintUtils::_machineFingerprint { QUuid() }; @@ -129,10 +141,10 @@ QString FingerprintUtils::getMachineFingerprintString() { #endif //Q_OS_WIN // Makes this hash unique to us - hash.addData("Vircadia"); + hash.addData(HASH_SALT); // Stretching - for (int i=0; i < 65535; i++) { + for (int i = 0; i < HASH_ITERATIONS; i++) { hash.addData(hash.result()); }