keygendr32/Keygender32/Generator.c
2024-03-20 23:09:10 -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;
}