#include "stdafx.h" #include "Random.h" #include "Generator.h" #include static const TCHAR szBaseChars[] = _T("BCDFGHJKMPQRTVWXY346789"); static const BYTE base = (sizeof(szBaseChars) / sizeof(TCHAR)) - 1; static const UINT64 uPrivKey[] = { 0x0a0d212073, 0x7468676972, 0x20736e617274 }; // Create an Adler32 checksum according to the provided szInput. static DWORD ck_adler32(LPCTSTR szInput, DWORD dwLen) { DWORD a = 1, b = 0, i; for (i = 0; i < dwLen; i++) { // XXX: This is a really naive way to "convert" to ANSI a += szInput[i] & 0xff; b += a; } a %= 65521; b %= 65521; return ((b << 16) | a); } // Encode a number as a "sanitized Microsoft" base-23 string static BOOL EncodeNumber(LPVOID lpIn, DWORD dwSize, LPTSTR szOut) { UINT64 uNum = 0; TCHAR *ptr = szOut + 5; if (!lpIn || !szOut) return FALSE; if (dwSize > 8) return FALSE; // XXX: Win32 is always little endian, so should be fine? CopyMemory(&uNum, lpIn, dwSize); *(ptr + 1) = 0; do { *ptr-- = szBaseChars[uNum % base]; uNum /= base; } while (ptr >= szOut); return TRUE; } BOOL GenerateKey(LPCTSTR szInput, LPTSTR szOut) { /* In the original implementation, this just generated random * "digits." I went too far with the bit, so now the "keys" have * some procedural generation! They're still structured similarly: * * XXXXX-YYYYY-ZZZZZ * * XXXXX is a random DWORD (shifted right 2 bytes to look more * random) and XORed by the first private key QWORD. * YYYYY is an Adler32 checksum of the user input, XORed by the * second private key QWORD. * Finally, ZZZZZ is the Adler32 checksum of "XXXXX-YYYYY", XORed * by the third private key QWORD. */ static BOOL bSeeded = FALSE; UINT64 uRandom; UINT64 dwChecksum, dwFinalSum; LPTSTR szPtr = szOut; if (!szInput || !szOut) return FALSE; if (!bSeeded) { xorsrand((unsigned)time(NULL)); bSeeded = TRUE; } // generate segment one uRandom = ((xorrand() & 0xffff) << 16) ^ uPrivKey[0]; if (!EncodeNumber(&uRandom, sizeof(UINT64), szPtr)) { return FALSE; } szPtr += 5; *szPtr++ = _T('-'); // ... and segment 2 dwChecksum = ck_adler32(szInput, (DWORD)_tcslen(szInput)) ^ uPrivKey[1]; if (!EncodeNumber(&dwChecksum, sizeof(DWORD), szPtr)) { return FALSE; } szPtr += 5; *szPtr++ = _T('-'); // ... finally, segment 3 dwFinalSum = ck_adler32(szOut, 11) ^ uPrivKey[2]; if (!EncodeNumber(&dwFinalSum, sizeof(DWORD), szPtr)) { return FALSE; } szPtr += 5; *szPtr = 0; return TRUE; }