/*
WickedDocs
(C) Copyright 2020
John Ryland
*/
#include "FingerPrint.h"
#include <stdio.h>
#include "Util.h"
#include "Crypto/Hash/SHA256.h"
#include "Crypto/Base64/Base64.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <algorithm>
#if defined(__linux__)
# include <linux/limits.h>
#endif
#if defined(__APPLE__)
# define DARWIN
#endif
#ifdef DARWIN
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/network/IOEthernetInterface.h>
#include <IOKit/network/IONetworkInterface.h>
#include <IOKit/network/IOEthernetController.h>
#include <DiskArbitration/DiskArbitration.h>
#include <mach-o/arch.h>
#include <sys/param.h>
#include <sys/mount.h>
// macOS specific
uint64_t GetMacAddress()
{
io_iterator_t intfIterator;
UInt8 MACAddress[kIOEthernetAddressSize] = { 0 };
// iterator for interfaces
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
if (matchingDict)
{
CFMutableDictionaryRef propertyMatchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (propertyMatchDict)
{
CFDictionarySetValue(propertyMatchDict, CFSTR(kIOPrimaryInterface), kCFBooleanTrue);
CFDictionarySetValue(matchingDict, CFSTR(kIOPropertyMatchKey), propertyMatchDict);
CFRelease(propertyMatchDict);
}
}
// iterate the interfaces
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &intfIterator) == KERN_SUCCESS)
{
io_object_t intfService;
io_object_t controllerService;
while ((intfService = IOIteratorNext(intfIterator)))
{
// obtain the mac address
CFDataRef MACAddressAsCFData;
if (IORegistryEntryGetParentEntry(intfService, kIOServicePlane, &controllerService) == KERN_SUCCESS)
{
MACAddressAsCFData = (CFDataRef)IORegistryEntryCreateCFProperty(controllerService, CFSTR(kIOMACAddress), kCFAllocatorDefault, 0);
if (MACAddressAsCFData)
{
// copy it
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
CFRelease(MACAddressAsCFData);
}
IOObjectRelease(controllerService);
}
IOObjectRelease(intfService);
}
}
// release the iterator.
IOObjectRelease(intfIterator);
// convert it to a 64bit number
uint64_t res = 0;
for (int i = 0; i < kIOEthernetAddressSize; i++)
{
res <<= 8;
res |= MACAddress[i];
}
return res;
}
#endif
/*
// This is not working on MAC
static QString MacAddress()
{
QNetworkConfiguration nc;
QNetworkConfigurationManager ncm;
QList<QNetworkConfiguration> configsForEth,configsForWLAN,allConfigs;
// getting all the configs we can
foreach (nc,ncm.allConfigurations(QNetworkConfiguration::Active))
{
if(nc.type() == QNetworkConfiguration::InternetAccessPoint)
{
// selecting the bearer type here
if(nc.bearerType() == QNetworkConfiguration::BearerWLAN)
{
configsForWLAN.append(nc);
}
if(nc.bearerType() == QNetworkConfiguration::BearerEthernet)
{
configsForEth.append(nc);
}
}
}
// further in the code WLAN's and Eth's were treated differently
allConfigs.append(configsForWLAN);
allConfigs.append(configsForEth);
QString MAC;
foreach(nc,allConfigs)
{
QNetworkSession networkSession(nc);
QNetworkInterface netInterface = networkSession.interface();
// these last two conditions are for omiting the virtual machines' MAC
// works pretty good since no one changes their adapter name
if(!(netInterface.flags() & QNetworkInterface::IsLoopBack)
&& !netInterface.humanReadableName().toLower().contains("vmware")
&& !netInterface.humanReadableName().toLower().contains("virtual"))
{
MAC = QString(netInterface.hardwareAddress());
return MAC;
//break;
}
}
foreach (QNetworkInterface netInterface, QNetworkInterface::allInterfaces())
{
// Return only the first non-loopback MAC Address
if (!(netInterface.flags() & QNetworkInterface::IsLoopBack))
return netInterface.hardwareAddress();
}
return QString();
}
*/
#if 0
#ifdef _WIN32
#include <windows.h>
#include <intrin.h>
#include <iphlpapi.h>
// we just need this for purposes of unique machine id.
// So any one or two mac's is fine.
u16 hashMacAddress( PIP_ADAPTER_INFO info )
{
u16 hash = 0;
for ( u32 i = 0; i < info->AddressLength; i++ )
{
hash += ( info->Address[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( u16& mac1, u16& mac2 )
{
IP_ADAPTER_INFO AdapterInfo[32];
DWORD dwBufLen = sizeof( AdapterInfo );
DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );
if ( dwStatus != ERROR_SUCCESS )
return; // no adapters.
PIP_ADAPTER_INFO pAdapterInfo = AdapterInfo;
mac1 = hashMacAddress( pAdapterInfo );
if ( pAdapterInfo->Next )
mac2 = hashMacAddress( pAdapterInfo->Next );
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
u16 tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
u16 getVolumeHash()
{
DWORD serialNum = 0;
// Determine if this volume uses an NTFS file system.
GetVolumeInformation( "c:\\", NULL, 0, &serialNum, NULL, NULL, NULL, 0 );
u16 hash = (u16)(( serialNum + ( serialNum >> 16 )) & 0xFFFF );
return hash;
}
u16 getCpuHash()
{
int cpuinfo[4] = { 0, 0, 0, 0 };
__cpuid( cpuinfo, 0 );
u16 hash = 0;
u16* ptr = (u16*)(&cpuinfo[0]);
for ( u32 i = 0; i < 8; i++ )
hash += ptr[i];
return hash;
}
const char* getMachineName()
{
static char computerName[1024];
DWORD size = 1024;
GetComputerName( computerName, &size );
return &(computerName[0]);
}
#else
#include "machine_id.h"
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef DARWIN
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <net/if_types.h>
#else //!DARWIN
#include <linux/if.h>
#include <linux/sockios.h>
#endif //!DARWIN
#include <sys/resource.h>
#include <sys/utsname.h>
//---------------------------------get MAC addresses ---------------------------------
// we just need this for purposes of unique machine id. So any one or two
// mac's is fine.
u16 hashMacAddress( u8* mac )
{
u16 hash = 0;
for ( u32 i = 0; i < 6; i++ )
{
hash += ( mac[i] << (( i & 1 ) * 8 ));
}
return hash;
}
void getMacHash( u16& mac1, u16& mac2 )
{
mac1 = 0;
mac2 = 0;
#ifdef DARWIN
struct ifaddrs* ifaphead;
if ( getifaddrs( &ifaphead ) != 0 )
return;
// iterate over the net interfaces
bool foundMac1 = false;
struct ifaddrs* ifap;
for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next )
{
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ))
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (u8*)(LLADDR(sdl))); //sdl->sdl_data) +
sdl->sdl_nlen) );
} else {
mac2 = hashMacAddress( (u8*)(LLADDR(sdl))); //sdl->sdl_data) +
sdl->sdl_nlen) );
break;
}
}
}
freeifaddrs( ifaphead );
#else // !DARWIN
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );
if ( sock < 0 ) return;
// enumerate all IP addresses of the system
struct ifconf conf;
char ifconfbuf[ 128 * sizeof(struct ifreq) ];
memset( ifconfbuf, 0, sizeof( ifconfbuf ));
conf.ifc_buf = ifconfbuf;
conf.ifc_len = sizeof( ifconfbuf );
if ( ioctl( sock, SIOCGIFCONF, &conf ))
{
assert(0);
return;
}
// get MAC address
bool foundMac1 = false;
struct ifreq* ifr;
for ( ifr = conf.ifc_req; (s8*)ifr < (s8*)conf.ifc_req + conf.ifc_len; ifr++ )
{
if ( ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data )
continue; // duplicate, skip it
if ( ioctl( sock, SIOCGIFFLAGS, ifr ))
continue; // failed to get flags, skip it
if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 )
{
if ( !foundMac1 )
{
foundMac1 = true;
mac1 = hashMacAddress( (u8*)&(ifr->ifr_addr.sa_data));
} else {
mac2 = hashMacAddress( (u8*)&(ifr->ifr_addr.sa_data));
break;
}
}
}
close( sock );
#endif // !DARWIN
// sort the mac addresses. We don't want to invalidate
// both macs if they just change order.
if ( mac1 > mac2 )
{
u16 tmp = mac2;
mac2 = mac1;
mac1 = tmp;
}
}
u16 getVolumeHash()
{
// we don't have a 'volume serial number' like on windows.
// Lets hash the system name instead.
u8* sysname = (u8*)getMachineName();
u16 hash = 0;
for ( u32 i = 0; sysname[i]; i++ )
hash += ( sysname[i] << (( i & 1 ) * 8 ));
return hash;
}
#ifdef DARWIN
#include <mach-o/arch.h>
u16 getCpuHash()
{
const NXArchInfo* info = NXGetLocalArchInfo();
u16 val = 0;
val += (u16)info->cputype;
val += (u16)info->cpusubtype;
return val;
}
u64 getSystemSerialNumberHash()
{
u64 hash = 0;
u8* phash = (u8*)&hash;
io_service_t platformExpert = IOServiceGetMatchingService( kIOMasterPortDefault, IOServiceMatching( "IOPlatformExpertDevice" ));
if ( !platformExpert ) return 0;
CFTypeRef t = IORegistryEntryCreateCFProperty( platformExpert, CFSTR( kIOPlatformSerialNumberKey ), kCFAllocatorDefault, 0 );
CFStringRef serialNumber = (CFStringRef)t;
if ( serialNumber )
{
const char* cs = (const char*) CFStringGetCStringPtr( serialNumber, kCFStringEncodingMacRoman );
u32 i = 0;
while ( *cs )
phash[i++%sizeof(u64)] ^= *cs++;
}
CFRelease( serialNumber );
IOObjectRelease( platformExpert );
return hash;
}
#else // !DARWIN
static void getCpuid( u32* p, u32 ax )
{
__asm __volatile
( "movl %%ebx, %%esi\n\t"
"cpuid\n\t"
"xchgl %%ebx, %%esi"
: "=a" (p[0]), "=S" (p[1]),
"=c" (p[2]), "=d" (p[3])
: "0" (ax)
);
}
u16 getCpuHash()
{
u32 cpuinfo[4] = { 0, 0, 0, 0 };
getCpuid( cpuinfo, 0 );
u16 hash = 0;
u32* ptr = (&cpuinfo[0]);
for ( u32 i = 0; i < 4; i++ )
hash += (ptr[i] & 0xFFFF) + ( ptr[i] >> 16 );
return hash;
}
#endif // !DARWIN
const char* getMachineName()
{
static struct utsname u;
if ( uname( &u ) < 0 )
{
assert(0);
return "unknown";
}
return u.nodename;
}
#endif
u16 mask[5] = { 0x4e25, 0xf4a1, 0x5437, 0xab41, 0x0000 };
static void smear( u16* id )
{
for ( u32 i = 0; i < 5; i++ )
for ( u32 j = i; j < 5; j++ )
if ( i != j )
id[i] ^= id[j];
for ( u32 i = 0; i < 5; i++ )
id[i] ^= mask[i];
}
static void unsmear( u16* id )
{
for ( u32 i = 0; i < 5; i++ )
id[i] ^= mask[i];
for ( u32 i = 0; i < 5; i++ )
for ( u32 j = 0; j < i; j++ )
if ( i != j )
id[4-i] ^= id[4-j];
}
static u16* computeSystemUniqueId()
{
static u16 id[5];
static bool computed = false;
if ( computed ) return id;
// produce a number that uniquely identifies this system.
id[0] = getCpuHash();
id[1] = getVolumeHash();
getMacHash( id[2], id[3] );
// fifth block is some checkdigits
id[4] = 0;
for ( u32 i = 0; i < 4; i++ )
id[4] += id[i];
smear( id );
computed = true;
return id;
}
const char* getSystemUniqueId()
{
// get the name of the computer
KxCbuf buf;
buf << getMachineName();
u16* id = computeSystemUniqueId();
for ( u32 i = 0; i < 5; i++ )
{
char num[16];
snprintf( num, 16, "%x", id[i] );
buf << "-";
switch( strlen( num ))
{
case 1: buf << "000"; break;
case 2: buf << "00"; break;
case 3: buf << "0"; break;
}
buf << num;
}
char* p = buf.getBuffer();
while ( *p ) { *p = toupper( *p ); p++; }
return KxSymbol( buf.getBuffer()).string();
}
static bool validate( KxSymbol testIdString )
{
// unpack the given string. parse failures return false.
KxCbuf testString;
testString << testIdString;
char* testName = strtok( testString.getBuffer(), "-" );
if ( !testName ) return false;
u16 testId[5];
for ( u32 i = 0; i < 5; i++ )
{
char* testNum = strtok( NULL, "-" );
if ( !testNum ) return false;
testId[i] = (u16)(strtol( testNum, NULL, 16 ));
}
unsmear( testId );
// make sure this id is valid - by looking at the checkdigits
u16 check = 0;
for ( u32 i = 0; i < 4; i++ )
check += testId[i];
if ( check != testId[4] ) return false;
// get the current system information
u16 systemId[5];
memcpy( systemId, computeSystemUniqueId(), sizeof( systemId ));
unsmear( systemId );
// now start scoring the match
u32 score = 0;
for ( u32 i = 0; i < 4; i++ )
if ( testId[i] == systemId[i] )
score++;
if ( !strcmp( getMachineName(), testName ))
score++;
// if we score 3 points or more then the id matches.
return ( score >= 3 ) ? true : false;
}
#endif
#ifdef DARWIN
// macOS specific
std::string UuidOfFile(const char* file)
{
char temp[64] = { 0 };
struct statfs b;
statfs(file, &b);
auto dict = DADiskCopyDescription(DADiskCreateFromBSDName(kCFAllocatorDefault, DASessionCreate(kCFAllocatorDefault), b.f_mntfromname));
CFStringGetCString(CFUUIDCreateString(kCFAllocatorDefault, (CFUUIDRef)CFDictionaryGetValue(dict, kDADiskDescriptionVolumeUUIDKey)), temp, 64, kCFStringEncodingUTF8);
return temp;
}
#else
std::string UuidOfFile(const char* file)
{
// TODO: need to implement
return file;
}
#endif
// Should work on Linux and macOS
static inline void do_cpuid(uint32_t selector, uint32_t *data)
{
__asm__ __volatile__ (
"xchg %%ebx, %k[tempreg]\n\t"
"cpuid\n\t"
"xchg %%ebx, %k[tempreg]\n"
: "=a" (data[0]),
[tempreg]"=&r" (data[1]),
"=c" (data[2]),
"=d" (data[3])
: "a"(selector),
"c"(0));
}
/*
static inline void getCpuid( u32* p, u32 ax )
{
__asm __volatile
(
"movl %%ebx, %%esi\n\t"
"cpuid\n\t"
"xchgl %%ebx, %%esi"
: "=a" (p[0]),
"=S" (p[1]),
"=c" (p[2]),
"=d" (p[3])
: "0" (ax)
);
}
u16 getCpuHash()
{
u32 cpuinfo[4] = { 0, 0, 0, 0 };
getCpuid( cpuinfo, 0 );
u16 hash = 0;
u32* ptr = (&cpuinfo[0]);
for ( u32 i = 0; i < 4; i++ )
hash += (ptr[i] & 0xFFFF) + ( ptr[i] >> 16 );
return hash;
}
*/
std::string CpuString()
{
/*
uint32_t data[4];
for (int sel = 1; sel < 5; ++sel)
{
do_cpuid( sel, data );
uint32_t c = data[3];
data[3] = data[2];
data[2] = c;
printf(" %x %x %x %x ", data[0], data[1], data[2], data[3]);
printf("\n");
}
*/
std::string cpuStr;
uint32_t data[4];
do_cpuid( 0, data );
data[0] = data[1];
data[1] = data[3];
// Get CPU brand / vendor_id
for (int i = 0; i < 12; i++)
if (((char*)data)[i])
cpuStr += ((char*)data)[i];
// The following are known ID strings from virtual machines:
// "xobVxobVxobV" - VirtualBox
// "VboxVboxVbox" - VirtualBox (maybe)
// "bhyve bhyve " – bhyve
// "KVMKVMKVM" – KVM
// "Microsoft Hv" – Microsoft Hyper-V or Windows Virtual PC
// " lrpepyh vr" – Parallels (it possibly should be "prl hyperv ", but it is encoded as " lrpepyh vr" due to an endianness mismatch)
// "VMwareVMware" – VMware
// "XenVMMXenVMM" – Xen HVM
// "ACRNACRNACRN" – Project ACRN
// Get model of the CPU / model_name
cpuStr += " ";
for (int sel = 2; sel < 4; ++sel)
{
do_cpuid( sel | 0x80000000, data );
for (int i = 0; i < 16; i++)
if (((char*)data)[i])
cpuStr += ((char*)data)[i];
}
// Not sure if VMs report fixed model or host model
// QEMU can report eg: "QEMU Virtual CPU version 2.0.0" (it returns GenuineIntel for vendor_id)
return cpuStr;
}
#if defined(_WIN32)
#include <direct.h>
static std::string GetRealPath(const std::string& dirName)
{
DWORD len = GetFullPathNameA(dirName.c_str(), 0, NULL, NULL);
std::string res(len, '-');
GetFullPathNameA(dirName.c_str(), len, &res[0], NULL);
printf("result of get real path of -%s- is -%s-\n", dirName.c_str(), res.c_str());
return res;
}
static bool getCurrentDirectory(char* dirName, size_t dirNameCapacity)
{
return _getcwd(dirName, dirNameCapacity);
}
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
}
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */
#include <unistd.h>
#include <libgen.h>
static std::string GetBaseName(const std::string& filePath)
{
const size_t len = filePath.size() + 1;
char tmp[len];
memcpy(tmp, filePath.c_str(), len);
return basename(tmp);
}
static std::string GetRealPath(const std::string& dirName)
{
std::string res(PATH_MAX, '-');
realpath(dirName.c_str(), &res[0]);
res = res.c_str(); // remove trailing \0 from string
return res;
}
static bool getCurrentDirectory(char* dirName, size_t dirNameCapacity)
{
return getcwd(dirName, dirNameCapacity);
}
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
pathName[pathNameSize] = '\0';
return pathNameSize;
}
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */
#include <mach-o/dyld.h>
#include <libgen.h>
static std::string GetBaseName(const std::string& filePath)
{
const size_t len = filePath.size() + 1;
char tmp[len];
memcpy(tmp, filePath.c_str(), len);
return basename(tmp);
}
static std::string GetRealPath(const std::string& dirName)
{
std::string res(PATH_MAX, '-');
realpath(dirName.c_str(), &res[0]);
res = res.c_str(); // remove trailing \0 from string
return res;
}
static bool getCurrentDirectory(char* dirName, size_t dirNameCapacity)
{
return getcwd(dirName, dirNameCapacity);
}
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
uint32_t pathNameSize = 0;
_NSGetExecutablePath(NULL, &pathNameSize);
if (pathNameSize > pathNameCapacity)
pathNameSize = pathNameCapacity;
if (!_NSGetExecutablePath(pathName, &pathNameSize))
{
char real[PATH_MAX];
if (realpath(pathName, real) != NULL)
{
pathNameSize = strlen(real);
strncpy(pathName, real, pathNameSize);
}
return pathNameSize;
}
return 0;
}
#else /* else of: #elif defined(__APPLE__) */
# error provide your own implementation
#endif /* end of: #if defined(_WIN32) */
std::string GetCurrentDirectory()
{
size_t siz = 32;
std::string exe(siz, '-');
while (!getCurrentDirectory(&exe[0], siz) && siz < 4096)
{
siz *= 2;
exe.resize(siz, '-');
}
if (siz >= 4096)
{
printf("Error 0x13d2\n");
exit(-1);
}
exe = exe.c_str(); // trim trailing \0 from size of string
return exe;
}
std::string GetExecutablePath()
{
size_t siz = 256;
std::string exe(siz, '-');
while (true)
{
size_t realSiz = getExecutablePathName(&exe[0], siz);
if (realSiz > 0 && realSiz < siz)
{
exe.resize(realSiz, '-');
break;
}
if (siz > 4096)
{
printf("Error 0x1342\n");
exit(-1);
}
siz *= 2;
exe.resize(siz, '-');
}
exe = exe.c_str(); // trim trailing \0 from size of string
return exe;
}
bool CheckApplicationName(const char* filePath)
{
std::string exe = GetExecutablePath();
std::string cwd = GetCurrentDirectory();
std::string file1 = filePath;
std::string file = GetRealPath(cwd + "/" + file1);
if (exe != file)
{
// printf("exe names don't match: -%s- != -%s+%s - %s-\n", exe.c_str(), cwd.c_str(), file1.c_str(), file.c_str());
printf("Error 0xa2e3f\n");
#ifdef _NDEBUG
exit(-1);
#endif
return false;
}
return true;
}
std::string ApplicationHash(const char* file)
{
char exePath[1024];
size_t siz = getExecutablePathName(exePath, 1024);
if (std::string(exePath) != file)
{
// printf("exe names don't match: -%s- != -%s-\n", exePath, file);
printf("Error 0xb2957\n");
exit(-1);
}
std::vector<uint8_t> exe;
if (!slurp(file, exe))
{
std::cout << "couldn't slurp " << file << std::endl;
return "";
}
uint32_t hash[8];
sha256(exe.data(), exe.size(), hash);
std::string b64;
std::vector<uint8_t> input_data((uint8_t*)hash, (uint8_t*)hash + 32);
if (!Base64::Encode(input_data, b64))
{
std::cout << "couldn't encode base64 " << file << std::endl;
return "";
}
return b64;
}
std::string SmudgedFingerPrint(const char* file)
{
uint32_t data[12 + 6];
do_cpuid( 0, data );
data[0] = data[1];
data[1] = data[3];
data[3] = (' ' << 24) | (':' << 16) | (':' << 8) | (' ' << 0);
do_cpuid( 0x80000002, &data[4] );
do_cpuid( 0x80000003, &data[8] );
uint64_t *fingerPrint = (uint64_t*)data;
std::string vol = UuidOfFile(file);
std::string vol2;
std::stringstream ss(vol);
std::string item;
while (std::getline(ss, item, '-'))
vol2 += item;
fingerPrint[6] = std::stoull(vol2.substr( 0, 16).c_str(), 0, 16);
fingerPrint[7] = std::stoull(vol2.substr(16, 16).c_str(), 0, 16);
fingerPrint[8] = GetMacAddress();
/*
printf("vol: %llx%llx\n", fingerPrint[6], fingerPrint[7]);
printf("mac: %llx\n", fingerPrint[8]);
printf("cpu: %s\n", (char*)fingerPrint);
*/
uint32_t position[18] = { 0, 11, 2, 5, 9, 15, 17, 8, 16, 4, 6, 13, 1, 14, 3, 10, 12, 7 };
uint32_t pattern[] = { 0x12345678, 0x87654321, 0x43218765, 0x56781234, 0x34127856, 0x65872143, 0x78563412, 0x21436587,
0x12563478, 0x87436521, 0x56127834, 0x43872165, 0x12345678, 0x87654321, 0x43218765, 0x56781234,
0x34127856, 0x65872143, 0x78563412, 0x21436587, 0x12563478, 0x87436521, 0x56127834, 0x43872165 };
uint32_t smudgedData[12 + 6];
// printf("FingerPrint: 0x");
for (int i = 0; i < 18; i++)
{
smudgedData[i] = data[position[i]] ^ pattern[i];
// printf("%08x", smudgedData[i]);
}
// printf("\n");
std::string b64;
std::vector<uint8_t> input_data((uint8_t*)smudgedData, (uint8_t*)smudgedData + 18*4);
Base64::Encode(input_data, b64);
// printf("vol: %s\n", vol2.c_str());
// printf("vol: -%llx- -%llx-\n", x1, x2);
// printf("mac: %llx\n", GetMacAddress());
return b64;
}
std::string DesmudgeFingerPrint(const char* smudge)
{
std::string s = smudge;
std::vector<uint8_t> d;
if (!Base64::Decode(s, d))
{
printf("error decoding base64\n");
return "";
}
uint32_t* smudgedData = (uint32_t*)d.data();
uint32_t position[18] = { 0, 11, 2, 5, 9, 15, 17, 8, 16, 4, 6, 13, 1, 14, 3, 10, 12, 7 };
uint32_t pattern[] = { 0x12345678, 0x87654321, 0x43218765, 0x56781234, 0x34127856, 0x65872143, 0x78563412, 0x21436587,
0x12563478, 0x87436521, 0x56127834, 0x43872165, 0x12345678, 0x87654321, 0x43218765, 0x56781234,
0x34127856, 0x65872143, 0x78563412, 0x21436587, 0x12563478, 0x87436521, 0x56127834, 0x43872165 };
uint32_t desmudgedData[12 + 6];
for (int i = 0; i < 18; i++)
{
desmudgedData[position[i]] = smudgedData[i] ^ pattern[i];
}
uint64_t *fingerPrint = (uint64_t*)desmudgedData;
char *cpuInfo = (char*)desmudgedData;
std::ostringstream oss;
oss << "Volume: " << std::setfill('0') << std::setw(16) << std::hex << fingerPrint[6];
oss << std::setfill('0') << std::setw(16) << std::hex << fingerPrint[7] << std::endl;
oss << "MACAddress: " << std::setfill('0') << std::setw(16) << std::hex << fingerPrint[8] << std::endl;
cpuInfo[ 12*4 ] = 0;
oss << "CPU: " << cpuInfo << std::endl;
return oss.str();
}