keygendr32/Keygender32/Generator.c
Will Springer 90ac8e2561 Normalize external includes to lowercase filenames
Also remove leading case of resource.h in the vcproj, since it's all lowercase
on the filesystem, and everything else refers to it like that.
2024-03-24 18:26:11 -07:00

116 lines
2.6 KiB
C

#include "stdafx.h"
#include "Random.h"
#include "Generator.h"
#include <time.h>
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;
}