116 lines
2.6 KiB
C
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;
|
||
|
}
|